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..4f21e2ef639 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,4 @@ +name: "CodeQL config" + +queries: + - uses: security-and-quality 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/.gitignore b/.gitignore index dc932d1f5c1..b14dab0a6b1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,3 @@ /codeql/ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json -.vscode diff --git a/.vscode/.gitattributes b/.vscode/.gitattributes new file mode 100644 index 00000000000..5fc4d971ee6 --- /dev/null +++ b/.vscode/.gitattributes @@ -0,0 +1 @@ +*.json linguist-language=JSON-with-Comments diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000000..8465a7c2f86 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "github.vscode-codeql" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000000..169b6bdd64d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + // To run a task, select the `Terminal | Run Task...` menu option, and then select the task from + // the list in the dropdown, or invoke the `Tasks: Run Task` command from the command palette/ + // To bind a keyboard shortcut to invoke a task, see https://code.visualstudio.com/docs/editor/tasks#_binding-keyboard-shortcuts-to-tasks. + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Sync Identical Files", + "type": "process", + // Non-Windows OS will usually have Python 3 already installed at /usr/bin/python3. + "command": "python3", + "args": [ + "config/sync-files.py", + "--latest" + ], + "group": "build", + "windows": { + // On Windows, use whatever Python interpreter is configured for this workspace. The default is + // just `python`, so if Python is already on the path, this will find it. + "command": "${config:python.pythonPath}", + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 8d4e4fd9b06..64bda94db77 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,11 +1,20 @@ -/cpp/ @Semmle/cpp-analysis -/csharp/ @Semmle/cs -/java/ @Semmle/java -/javascript/ @Semmle/js -/python/ @Semmle/python +/cpp/ @github/codeql-c-analysis +/csharp/ @github/codeql-csharp +/java/ @github/codeql-java +/javascript/ @github/codeql-javascript +/python/ @github/codeql-python + +# Assign query help for docs review /cpp/**/*.qhelp @hubwriter /csharp/**/*.qhelp @jf205 /java/**/*.qhelp @felicitymay /javascript/**/*.qhelp @mchammer01 /python/**/*.qhelp @felicitymay /docs/language/ @shati-patel @jf205 + +# Exclude help for experimental queries from docs review +/cpp/**/experimental/**/*.qhelp @github/codeql-c-analysis +/csharp/**/experimental/**/*.qhelp @github/codeql-csharp +/java/**/experimental/**/*.qhelp @github/codeql-java +/javascript/**/experimental/**/*.qhelp @github/codeql-javascript +/python/**/experimental/**/*.qhelp @github/codeql-python diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fcece36b0b1..641b30ebe3f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,39 +1,126 @@ -# Code of Conduct +## Our Pledge -This code of conduct outlines expectations for participation in the Semmle open source community, including any open source repositories on GitHub.com, as well as steps for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. -People violating this code of conduct may be banned from the community. +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. -Our community strives to: -* Be friendly and patient: Remember you might not be communicating in someone else’s primary spoken or programming language, and others may not have your level of understanding. -* Be welcoming: Our community welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. -* Be respectful: We are a world-wide community of professionals, and we conduct ourselves professionally. Disagreement is no excuse for poor behavior and poor manners. Disrespectful and unacceptable behavior includes, but is not limited to: - * Violent threats or language. - * Discriminatory or derogatory jokes and language. - * Posting sexually explicit or violent material. - * Posting, or threatening to post, people’s personally identifying information (“doxing”). - * Insults, especially those using discriminatory terms or slurs. - * Behavior that could be perceived as sexual attention. - * Advocating for or encouraging any of the above behaviors. -* Understand disagreements: Disagreements, both social and technical, are useful learning opportunities. Seek to understand others’ viewpoints and resolve differences constructively. +## Our Standards -This code is not exhaustive or complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter. +Examples of behavior that contributes to a positive environment for our +community include: -# Scope +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community -This code of conduct applies to all repositories and communities for Semmle open source projects, regardless of whether or not the repository explicitly calls out its use of this code. The code also applies in public spaces when an individual is representing the Semmle open source community. Examples include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. +Examples of unacceptable behavior include: +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting -# Reporting Code of Conduct Issues -We encourage members of the community to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting code-of-conduct@semmle.com. -In your report please include: -* Your contact information. -* Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. -* Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment. -* Any additional information that may be helpful. +## Enforcement Responsibilities -All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never part of the review team. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take any action they deem appropriate, including a permanent ban from the community. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. -*This text is licensed under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license. It is based on a template established by the [TODO Group](http://todogroup.org/) and variants thereof used by numerous other large communities (e.g., [Microsoft](https://microsoft.github.io/codeofconduct/), [Facebook](https://code.fb.com/codeofconduct/), [Yahoo](https://yahoo.github.io/codeofconduct), [Twitter](https://github.com/twitter/code-of-conduct), [GitHub](https://blog.github.com/2015-07-20-adopting-the-open-code-of-conduct/)) and the Scope section from the [Contributor Covenant version 1.4](http://contributor-covenant.org/version/1/4/).* +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +opensource@github.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9853e6b91b8..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 @@ -20,7 +20,7 @@ If you have an idea for a query that you would like to share with other CodeQL u * Python: `python/ql/src` Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose. - - Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/Semmle/ql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`. + - Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`. - The structure of an `experimental` subdirectory mirrors the structure of its parent directory. - Select or create an appropriate directory in `experimental` based on the existing directory structure of `experimental` or its parent directory. @@ -32,11 +32,11 @@ 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** - - The queries and libraries must be [autoformatted](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting). + - The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html). 4. **Compilation** @@ -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 1f77856cfc4..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? @@ -9,8 +9,20 @@ You can use the [interactive query console](https://lgtm.com/help/lgtm/using-que ## Contributing -We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/Semmle/ql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. +We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. ## License -The code in this repository is licensed under [Apache License 2.0](LICENSE) by [GitHub](https://github.com). +The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com). + +## Visual Studio Code integration + +If you use Visual Studio Code to work in this repository, there are a few integration features to make development easier. + +### CodeQL for Visual Studio Code + +You can install the [CodeQL for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-codeql) extension to get syntax highlighting, IntelliSense, and code navigation for the QL language, as well as unit test support for testing CodeQL libraries and queries. + +### Tasks + +The `.vscode/tasks.json` file defines custom tasks specific to working in this repository. To invoke one of these tasks, select the `Terminal | Run Task...` menu option, and then select the desired task from the dropdown. You can also invoke the `Tasks: Run Task` command from the command palette. diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md index 7ab002857cf..a89a360de3e 100644 --- a/change-notes/1.24/analysis-cpp.md +++ b/change-notes/1.24/analysis-cpp.md @@ -4,6 +4,8 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## General improvements +You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). + ## New queries | **Query** | **Tags** | **Purpose** | @@ -12,46 +14,71 @@ The following changes in version 1.24 affect C/C++ analysis in all applications. ## Changes to existing queries +A new taint-tracking library is used by all the security queries that track tainted values +(`cpp/path-injection`, `cpp/cgi-xss`, `cpp/sql-injection`, `cpp/uncontrolled-process-operation`, +`cpp/unbounded-write`, `cpp/tainted-format-string`, `cpp/tainted-format-string-through-global`, +`cpp/uncontrolled-arithmetic`, `cpp/uncontrolled-allocation-size`, `cpp/user-controlled-bypass`, +`cpp/cleartext-storage-buffer`, `cpp/tainted-permissions-check`). +These queries now have more precise results and also offer _path explanations_ so you can explore the results easily. +There is a performance cost to this, and the LGTM query suite will overall run slower than before. + | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Boost\_asio TLS Settings Misconfiguration (`cpp/boost/tls-settings-misconfiguration`) | Query id change | The identifier was updated to use dashes in place of underscores (previous identifier `cpp/boost/tls_settings_misconfiguration`). | | Buffer not sufficient for string (`cpp/overflow-calculated`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | +| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | | Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | | Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. | -| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Fixed false positive results in template code. | -| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. | -| Missing return statement (`cpp/missing-return`) | More accurate locations | Locations reported by this query are now more accurate in some cases. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. | -| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. | -| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. | -| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | Cases where the tainted allocation size is range checked are now more reliably excluded. | +| Mismatching new/free or malloc/delete (`cpp/new-free-mismatch`) | Fewer false positive results | Improved handling of template code gives greater precision. | +| Missing return statement (`cpp/missing-return`) | Fewer false positive results and more accurate locations | Functions containing `asm` statements are no longer highlighted by this query. The locations reported by this query are now more accurate in some cases. | +| No space for zero terminator (`cpp/no-space-for-terminator`) | More results with greater precision | The query gives more precise results for a wider variety of buffer allocations. String arguments to formatting functions are now (usually) expected to be null terminated strings. Use of the `semmle.code.cpp.models.interfaces.Allocation` library identifies problems with a wider variety of buffer allocations. This query is also more conservative when identifying which pointers point to null-terminated strings. | +| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | Fewer false positive results | The query now produces fewer, more accurate results. Cases where the tainted allocation size is range checked are more reliably excluded. | | Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. | +| Pointer overflow check (`cpp/pointer-overflow-check`),
Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`),
Signed overflow check (`cpp/signed-overflow-check`) | More correct results | A new library is used for determining which expressions have identical value, giving more precise results. There is a performance cost to this, and the LGTM suite will overall run slower than before. | | Unsafe array for days of the year (`cpp/leap-year/unsafe-array-for-days-of-the-year`) | | This query is no longer run on LGTM. | | Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | More correct results | This query now also looks for comparisons of the form `0 <= x`. | ## Changes to libraries -* The data-flow library has been improved, which affects and improves some security queries. The improvements are: - - Track flow through functions that combine taint tracking with flow through fields. - - Track flow through clone-like functions, that is, functions that read contents of a field from a - parameter and stores the value in the field of a returned object. -* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model allocation such as `new` expressions and calls to `malloc`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface. -* Created the `semmle.code.cpp.models.interfaces.Deallocation` library to model deallocation such as `delete` expressions and calls to `free`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface. +* The built-in C++20 "spaceship operator" (`<=>`) is now supported via the QL + class `SpaceshipExpr`. Overloaded forms are modeled as calls to functions + named `operator<=>`. +* The data-flow library (`semmle.code.cpp.dataflow.DataFlow` and + `semmle.code.cpp.dataflow.TaintTracking`) has been improved, which affects + and improves some security queries. The improvements are: + - Track flow through functions that combine taint tracking with flow through fields. + - Track flow through clone-like functions, that is, functions that read contents of a field from a + parameter and stores the value in the field of a returned object. +* The security pack taint tracking library + (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate + representation. This provides a more precise analysis of flow through + parameters and pointers. For new queries, however, we continue to recommend + using `semmle.code.cpp.dataflow.TaintTracking`. +* The global value numbering library + (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new + intermediate representation to provide a more precise analysis of + heap-allocated memory and pointers to stack variables. +* New libraries have been created to provide a more consistent and useful interface + for modeling allocation and deallocation. These replace the old + `semmle.code.cpp.commons.Alloc` library. + * The new `semmle.code.cpp.models.interfaces.Allocation` library models + allocations, such as `new` expressions and calls to `malloc`. + * The new `semmle.code.cpp.models.interfaces.Deallocation` library + models deallocations, such as `delete` expressions and calls to `free`. + * The predicate `freeCall` in `semmle.code.cpp.commons.Alloc` has been + deprecated. The `Allocation` and `Deallocation` models in + `semmle.code.cpp.models.interfaces` should be used instead. * The new class `StackVariable` should be used in place of `LocalScopeVariable` in most cases. The difference is that `StackVariable` does not include variables declared with `static` or `thread_local`. - * As a rule of thumb, custom queries about the _values_ of variables should - be changed from `LocalScopeVariable` to `StackVariable`, while queries - about the _name or scope_ of variables should remain unchanged. - * The `LocalScopeVariableReachability` library is deprecated in favor of - `StackVariableReachability`. The functionality is the same. -* The models library models `strlen` in more detail, and includes common variations such as `wcslen`. -* The models library models `gets` and similar functions. -* The models library now partially models `std::string`. -* The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had - the following improvements: - * The library now models data flow through `strdup` and similar functions. - * The library now models data flow through formatting functions such as `sprintf`. -* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) uses a new intermediate representation. This provides a more precise analysis of pointers to stack variables and flow through parameters, improving the results of many security queries. -* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering`) uses a new intermediate representation to provide a more precise analysis of heap allocated memory and pointers to stack variables. -* `freeCall` in `semmle.code.cpp.commons.Alloc` has been deprecated. The`Allocation` and `Deallocation` models in `semmle.code.cpp.models.interfaces` should be used instead. + * As a rule of thumb, custom queries about the _values_ of variables should + be changed from `LocalScopeVariable` to `StackVariable`, while queries + about the _name or scope_ of variables should remain unchanged. + * The `LocalScopeVariableReachability` library is deprecated in favor of + `StackVariableReachability`. The functionality is the same. +* Taint tracking and data flow now features better modeling of commonly-used + library functions: + * `gets` and similar functions, + * the most common operations on `std::string`, + * `strdup` and similar functions, and + * formatting functions such as `sprintf`. diff --git a/change-notes/1.24/analysis-csharp.md b/change-notes/1.24/analysis-csharp.md index a745e985eae..3ed64a6b27b 100644 --- a/change-notes/1.24/analysis-csharp.md +++ b/change-notes/1.24/analysis-csharp.md @@ -2,30 +2,31 @@ The following changes in version 1.24 affect C# analysis in all applications. +## General improvements + +You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). + ## New queries | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| -| Assembly path injection (`cs/assembly-path-injection`) | security, external/cwe/cwe-114 | Finds user-controlled data used to load an assembly. | -| Insecure configuration for ASP.NET requestValidationMode (`cs/insecure-request-validation-mode`) | security, external/cwe/cwe-016 | Finds where this attribute has been set to a value less than 4.5, which turns off some validation features and makes the application less secure. | -| Insecure SQL connection (`cs/insecure-sql-connection`) | security, external/cwe/cwe-327 | Finds unencrypted SQL connection strings. | -| Page request validation is disabled (`cs/web/request-validation-disabled`) | security, frameworks/asp.net, external/cwe/cwe-016 | Finds where ASP.NET page request validation has been disabled, which could make the application less secure. | -| Serialization check bypass (`cs/serialization-check-bypass`) | security, external/cwe/cwe-20 | Finds where data is not validated in a deserialization method. | -| XML injection (`cs/xml-injection`) | security, external/cwe/cwe-091 | Finds user-controlled data that is used to write directly to an XML document. | +| Assembly path injection (`cs/assembly-path-injection`) | security, external/cwe/cwe-114 | Finds user-controlled data used to load an assembly. Results are shown on LGTM by default. | +| Insecure configuration for ASP.NET requestValidationMode (`cs/insecure-request-validation-mode`) | security, external/cwe/cwe-016 | Finds where this attribute has been set to a value less than 4.5, which turns off some validation features and makes the application less secure. By default, the query is not run on LGTM. | +| Insecure SQL connection (`cs/insecure-sql-connection`) | security, external/cwe/cwe-327 | Finds unencrypted SQL connection strings. Results are not shown on LGTM by default. | +| Page request validation is disabled (`cs/web/request-validation-disabled`) | security, frameworks/asp.net, external/cwe/cwe-016 | Finds where ASP.NET page request validation has been disabled, which could make the application less secure. By default, the query is not run on LGTM. | +| Serialization check bypass (`cs/serialization-check-bypass`) | security, external/cwe/cwe-20 | Finds where data is not validated in a deserialization method. Results are not shown on LGTM by default. | +| XML injection (`cs/xml-injection`) | security, external/cwe/cwe-091 | Finds user-controlled data that is used to write directly to an XML document. Results are shown on LGTM by default. | ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. | -| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. | | Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. | -| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. | -| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. | -| Information exposure through transmitted data (`cs/sensitive-data-transmission`) | More results | The query now recognizes writes to cookies and writes to ASP.NET (`Inner`)`Text` properties as additional sinks. | | Information exposure through an exception (`cs/information-exposure-through-exception`) | More results | The query now recognizes writes to cookies, writes to ASP.NET (`Inner`)`Text` properties, and email contents as additional sinks. | - -## Removal of old queries +| Information exposure through transmitted data (`cs/sensitive-data-transmission`) | More results | The query now recognizes writes to cookies and writes to ASP.NET (`Inner`)`Text` properties as additional sinks. | +| Potentially dangerous use of non-short-circuit logic (`cs/non-short-circuit`) | Fewer false positive results | Results have been removed when the expression contains an `out` parameter. | +| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the value assigned is an (implicitly or explicitly) cast default-like value. For example, `var s = (string)null` and `string s = default`. Results have also been removed when the variable is named `_` in a `foreach` statement. | +| XPath injection (`cs/xml/xpath-injection`) | More results | The query now recognizes calls to methods on `System.Xml.XPath.XPathNavigator` objects. | ## Changes to code extraction @@ -37,13 +38,11 @@ The following changes in version 1.24 affect C# analysis in all applications. ## Changes to libraries * The data-flow library has been improved, which affects and improves most security queries. The improvements are: - - Track flow through methods that combine taint tracking with flow through fields. - - Track flow through clone-like methods, that is, methods that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through methods that combine taint tracking with flow through fields. + - Track flow through clone-like methods, that is, methods that read the contents of a field from a + parameter and store the value in the field of a returned object. * The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls. * [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods. * Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`. * `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`. -* A new class `RemoteFlowSink` has been added to model sinks where data might be exposed to external users. Examples include web page output, e-mails, and cookies. - -## Changes to autobuilder +* A new class `RemoteFlowSink` has been added to model sinks where data might be exposed to external users. Examples include web page output, emails, and cookies. diff --git a/change-notes/1.24/analysis-java.md b/change-notes/1.24/analysis-java.md index 36210c0457e..a594cf08e1e 100644 --- a/change-notes/1.24/analysis-java.md +++ b/change-notes/1.24/analysis-java.md @@ -4,7 +4,7 @@ The following changes in version 1.24 affect Java analysis in all applications. ## General improvements -* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). +* You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). * A `Customizations.qll` file has been added to allow customizations of the standard library that apply to all queries. ## New queries @@ -21,16 +21,16 @@ The following changes in version 1.24 affect Java analysis in all applications. | **Query** | **Expected impact** | **Change** | |------------------------------|------------------------|-----------------------------------| -| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Final fields with a non-null initializer are no longer reported. | -| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. | -| Useless null check (`java/useless-null-check`) | More true positives | Useless checks on final fields with a non-null initializer are now reported. | +| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positive results | Final fields with a non-null initializer are no longer reported. | +| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positive results | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. | +| Useless null check (`java/useless-null-check`) | More true positive results | Useless checks on final fields with a non-null initializer are now reported. | ## Changes to libraries * The data-flow library has been improved, which affects and improves most security queries. The improvements are: - - Track flow through methods that combine taint tracking with flow through fields. - - Track flow through clone-like methods, that is, methods that read contents of a field from a - parameter and stores the value in the field of a returned object. + - Track flow through methods that combine taint tracking with flow through fields. + - Track flow through clone-like methods, that is, methods that read contents of a field from a + parameter and stores the value in the field of a returned object. * Identification of test classes has been improved. Previously, one of the match conditions would classify any class with a name containing the string "Test" as a test class, but now this matching has been replaced with one that @@ -38,6 +38,6 @@ The following changes in version 1.24 affect Java analysis in all applications. general file classification mechanism and thus suppression of alerts, and also any security queries using taint tracking, as test classes act as default barriers stopping taint flow. -* Parentheses are now no longer modelled directly in the AST, that is, the +* Parentheses are now no longer modeled directly in the AST, that is, the `ParExpr` class is empty. Instead, a parenthesized expression can be identified with the `Expr.isParenthesized()` member predicate. diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md index 0e92d66033d..ee776a61acb 100644 --- a/change-notes/1.24/analysis-javascript.md +++ b/change-notes/1.24/analysis-javascript.md @@ -4,67 +4,68 @@ * TypeScript 3.8 is now supported. -* Alert suppression can now be done with single-line block comments (`/* ... */`) as well as line comments (`// ...`). +* You can now suppress alerts using either single-line block comments (`/* ... */`) or line comments (`// ...`). * Resolution of imports has improved, leading to more results from the security queries: - - Imports with the `.js` extension can now be resolved to a TypeScript file, - when the import refers to a file generated by TypeScript. - - Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved. - - Export declarations of the form `export * as ns from "x"` are now analyzed more precisely. + - Imports with the `.js` extension can now be resolved to a TypeScript file, + when the import refers to a file generated by TypeScript. + - Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved. + - Export declarations of the form `export * as ns from "x"` are now analyzed more precisely. * The analysis of sanitizers has improved, leading to more accurate results from the security queries. In particular: - - Sanitizer guards now act across function boundaries in more cases. - - Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value. + - Sanitizer guards now act across function boundaries in more cases. + - Sanitizers can now better distinguish between a tainted value and an object _containing_ a tainted value. * Call graph construction has been improved, leading to more results from the security queries: - - Calls can now be resolved to indirectly-defined class members in more cases. - - Calls through partial invocations such as `.bind` can now be resolved in more cases. + - Calls can now be resolved to indirectly-defined class members in more cases. + - Calls through partial invocations such as `.bind` can now be resolved in more cases. * Support for flow summaries has been more clearly marked as being experimental and moved to the new `experimental` folder. * Support for the following frameworks and libraries has been improved: - - [Electron](https://electronjs.org/) - - [fstream](https://www.npmjs.com/package/fstream) - - [Handlebars](https://www.npmjs.com/package/handlebars) - - [jsonfile](https://www.npmjs.com/package/jsonfile) - - [Koa](https://www.npmjs.com/package/koa) - - [Node.js](https://nodejs.org/) - - [Socket.IO](https://socket.io/) - - [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) - - [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface) - - [for-in](https://www.npmjs.com/package/for-in) - - [for-own](https://www.npmjs.com/package/for-own) - - [http2](https://nodejs.org/api/http2.html) - - [jQuery](https://jquery.com/) - - [lazy-cache](https://www.npmjs.com/package/lazy-cache) - - [mongodb](https://www.npmjs.com/package/mongodb) - - [ncp](https://www.npmjs.com/package/ncp) - - [node-dir](https://www.npmjs.com/package/node-dir) - - [path-exists](https://www.npmjs.com/package/path-exists) - - [pg](https://www.npmjs.com/package/pg) - - [react](https://www.npmjs.com/package/react) - - [recursive-readdir](https://www.npmjs.com/package/recursive-readdir) - - [request](https://www.npmjs.com/package/request) - - [rimraf](https://www.npmjs.com/package/rimraf) - - [send](https://www.npmjs.com/package/send) - - [SockJS](https://www.npmjs.com/package/sockjs) - - [SockJS-client](https://www.npmjs.com/package/sockjs-client) - - [typeahead.js](https://www.npmjs.com/package/typeahead.js) - - [vinyl-fs](https://www.npmjs.com/package/vinyl-fs) - - [write-file-atomic](https://www.npmjs.com/package/write-file-atomic) - - [ws](https://github.com/websockets/ws) + - [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface) + - [Electron](https://electronjs.org/) + - [for-in](https://www.npmjs.com/package/for-in) + - [for-own](https://www.npmjs.com/package/for-own) + - [fstream](https://www.npmjs.com/package/fstream) + - [Handlebars](https://www.npmjs.com/package/handlebars) + - [http2](https://nodejs.org/api/http2.html) + - [jQuery](https://jquery.com/) + - [jsonfile](https://www.npmjs.com/package/jsonfile) + - [Koa](https://www.npmjs.com/package/koa) + - [lazy-cache](https://www.npmjs.com/package/lazy-cache) + - [mongodb](https://www.npmjs.com/package/mongodb) + - [ncp](https://www.npmjs.com/package/ncp) + - [Node.js](https://nodejs.org/) + - [node-dir](https://www.npmjs.com/package/node-dir) + - [path-exists](https://www.npmjs.com/package/path-exists) + - [pg](https://www.npmjs.com/package/pg) + - [react](https://www.npmjs.com/package/react) + - [recursive-readdir](https://www.npmjs.com/package/recursive-readdir) + - [request](https://www.npmjs.com/package/request) + - [rimraf](https://www.npmjs.com/package/rimraf) + - [send](https://www.npmjs.com/package/send) + - [Socket.IO](https://socket.io/) + - [SockJS](https://www.npmjs.com/package/sockjs) + - [SockJS-client](https://www.npmjs.com/package/sockjs-client) + - [typeahead.js](https://www.npmjs.com/package/typeahead.js) + - [vinyl-fs](https://www.npmjs.com/package/vinyl-fs) + - [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) + - [write-file-atomic](https://www.npmjs.com/package/write-file-atomic) + - [ws](https://github.com/websockets/ws) + ## New queries | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. | -| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. | | Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. | | Polynomial regular expression used on uncontrolled data (`js/polynomial-redos`) | security, external/cwe/cwe-730, external/cwe/cwe-400 | Highlights expensive regular expressions that may be used on malicious input. Results are shown on LGTM by default. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive assignment operations that are susceptible to prototype pollution. Results are shown on LGTM by default. | -| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. | +| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. | +| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. | | Unnecessary use of `cat` process (`js/unnecessary-use-of-cat`) | correctness, security, maintainability | Highlights command executions of `cat` where the fs API should be used instead. Results are shown on LGTM by default. | @@ -73,20 +74,20 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| | Clear-text logging of sensitive information (`js/clear-text-logging`) | More results | More results involving `process.env` and indirect calls to logging methods are recognized. | -| Duplicate parameter names (`js/duplicate-parameter-name`) | Fewer results | This query now recognizes additional parameters that reasonably can have duplicated names. | -| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes additional cases where a single replacement is likely to be intentional. | -| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | +| Duplicate parameter names (`js/duplicate-parameter-name`) | Fewer results | This query now ignores additional parameters that reasonably can have duplicated names. | | Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. | -| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | +| Identical operands (`js/redundant-operation`) | Fewer results | This query now excludes cases where the operands change a value using ++/-- expressions. | +| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This query now recognizes and excludes additional cases where a single replacement is likely to be intentional. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional variations of URL scheme checks. | | Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. | +| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now excludes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | | Syntax error (`js/syntax-error`) | Lower severity | This results of this query are now displayed with lower severity. | -| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes additional cases that do not require secure hashing. | -| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes escapes in strings and regular expression literals. | -| Identical operands (`js/redundant-operation`) | Fewer results | This query now recognizes cases where the operands change a value using ++/-- expressions. | -| Superfluous trailing arguments (`js/superfluous-trailing-arguments`) | Fewer results | This query now recognizes cases where a function uses the `Function.arguments` value to process a variable number of parameters. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more variations of URL scheme checks. | +| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed and used. | +| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | +| Use of password hash with insufficient computational effort (`js/insufficient-password-hash`) | Fewer false positive results | This query now recognizes and excludes additional cases that do not require secure hashing. | +| Useless regular-expression character escape (`js/useless-regexp-character-escape`) | Fewer false positive results | This query now distinguishes between escapes in strings and regular expression literals. | ## Changes to libraries @@ -94,6 +95,6 @@ * An extensible model of the `EventEmitter` pattern has been implemented. * Taint-tracking configurations now interact differently with the `data` flow label, which may affect queries that combine taint-tracking and flow labels. - - Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label. - - Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object. - To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer. + - Sources added by the 1-argument `isSource` predicate are associated with the `taint` label now, instead of the `data` label. + - Sanitizers now only block the `taint` label. As a result, sanitizers no longer block the flow of tainted values wrapped inside a property of an object. + To retain the old behavior, instead use a barrier, or block the `data` flow label using a labeled sanitizer. diff --git a/change-notes/1.24/analysis-python.md b/change-notes/1.24/analysis-python.md index fe5e637f041..16a3d4156e4 100644 --- a/change-notes/1.24/analysis-python.md +++ b/change-notes/1.24/analysis-python.md @@ -4,37 +4,52 @@ The following changes in version 1.24 affect Python analysis in all applications ## General improvements -Support for Django version 2.x and 3.x +- Support for Django version 2.x and 3.x -## New queries +- Taint tracking now correctly tracks taint in destructuring assignments. For example, if `tainted_list` is a list of tainted tainted elements, then + ```python + head, *tail = tainted_list + ``` + will result in `tail` being tainted with the same taint as `tainted_list`, and `head` being tainted with the taint of the elements of `tainted_list`. + +- A large number of libraries and queries have been moved to the new `Value` API, which should result in more precise results. + +- The `Value` interface has been extended in various ways: + - A new `StringValue` class has been added, for tracking string literals. + - Values now have a `booleanValue` method which returns the boolean interpretation of the given value. + - Built-in methods for which the return type is not fixed are now modeled as returning an unknown value by default. -| **Query** | **Tags** | **Purpose** | -|-----------------------------|-----------|--------------------------------------------------------------------| ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| -| Uncontrolled command line (`py/command-line-injection`) | More results | We now model the `fabric` and `invoke` pacakges for command execution. | +| Arbitrary file write during tarfile extraction (`py/tarslip`) | Fewer false negative results | Negations are now handled correctly in conditional expressions that may sanitize tainted values. | +| First parameter of a method is not named 'self' (`py/not-named-self`) | Fewer false positive results | `__class_getitem__` is now recognized as a class method. | +| Import of deprecated module (`py/import-deprecated-module`) | Fewer false positive results | Deprecated modules that are used to provide backwards compatibility are no longer reported.| +| Module imports itself (`py/import-own-module`) | Fewer false positive results | Imports local to a given package are no longer classified as self-imports. | +| Uncontrolled command line (`py/command-line-injection`) | More results | We now model the `fabric` and `invoke` packages for command execution. | ### Web framework support -The QL-library support for the web frameworks Bottle, CherryPy, Falcon, Pyramid, TurboGears, Tornado, and Twisted have -been fixed so they provide a proper HttpRequestTaintSource, instead of a TaintSource. This will enable results for the following queries: +The CodeQL library has improved support for the web frameworks: Bottle, CherryPy, Falcon, Pyramid, TurboGears, Tornado, and Twisted. They now provide a proper `HttpRequestTaintSource`, instead of a `TaintSource`. This will enable results for the following queries: -- py/path-injection -- py/command-line-injection -- py/reflective-xss -- py/sql-injection -- py/code-injection -- py/unsafe-deserialization -- py/url-redirection +- `py/path-injection` +- `py/command-line-injection` +- `py/reflective-xss` +- `py/sql-injection` +- `py/code-injection` +- `py/unsafe-deserialization` +- `py/url-redirection` -The QL-library support for the web framework Twisted have been fixed so they provide a proper -HttpResponseTaintSink, instead of a TaintSink. This will enable results for the following +The library also has improved support for the web framework Twisted. It now provides a proper +`HttpResponseTaintSink`, instead of a `TaintSink`. This will enable results for the following queries: -- py/reflective-xss -- py/stack-trace-exposure +- `py/reflective-xss` +- `py/stack-trace-exposure` ## Changes to libraries +### Taint tracking +- The `urlsplit` and `urlparse` functions now propagate taint appropriately. +- HTTP requests using the `requests` library are now modeled. diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md new file mode 100644 index 00000000000..7ab98ffe859 --- /dev/null +++ b/change-notes/1.25/analysis-cpp.md @@ -0,0 +1,44 @@ +# 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** | +|----------------------------|------------------------|------------------------------------------------------------------| + +## 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 new file mode 100644 index 00000000000..5a99e47cc39 --- /dev/null +++ b/change-notes/1.25/analysis-javascript.md @@ -0,0 +1,89 @@ +# Improvements to JavaScript analysis + +## 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) + - [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) + - [minimongo](https://www.npmjs.com/package/minimongo/) + - [mssql](https://www.npmjs.com/package/mssql) + - [mysql](https://www.npmjs.com/package/mysql) + - [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) + - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) + +* TypeScript 3.9 is now supported. + +* 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. | +| 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. | + +## 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. | +| 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. | +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| 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. | +| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| 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". 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..35c9169df56 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -53,114 +53,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 +185,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 +212,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 +225,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 +289,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/sync-files.py b/config/sync-files.py index 30be173c18b..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") @@ -107,7 +119,7 @@ def choose_latest_file(files): local_error_count = 0 def emit_local_error(path, line, error): - print('ERROR: ' + path + ':' + line + " - " + error) + print('ERROR: ' + path + ':' + str(line) + " - " + error) global local_error_count local_error_count += 1 diff --git a/cpp/ql/src/Critical/FileClosed.qll b/cpp/ql/src/Critical/FileClosed.qll index 1e782259156..e2ba3c25b81 100644 --- a/cpp/ql/src/Critical/FileClosed.qll +++ b/cpp/ql/src/Critical/FileClosed.qll @@ -1,5 +1,6 @@ import semmle.code.cpp.pointsto.PointsTo +/** Holds if there exists a call to a function that might close the file specified by `e`. */ predicate closed(Expr e) { fcloseCall(_, e) or exists(ExprCall c | @@ -8,10 +9,19 @@ predicate closed(Expr e) { ) } +/** An expression for which there exists a function call that might close it. */ class ClosedExpr extends PointsToExpr { ClosedExpr() { closed(this) } override predicate interesting() { closed(this) } } +/** + * Holds if `fc` is a call to a function that opens a file that might be closed. For example: + * ``` + * FILE* f = fopen("file.txt", "r"); + * ... + * fclose(f); + * ``` + */ predicate fopenCallMayBeClosed(FunctionCall fc) { fopenCall(fc) and anythingPointsTo(fc) } diff --git a/cpp/ql/src/Critical/LoopBounds.qll b/cpp/ql/src/Critical/LoopBounds.qll index f10e62c909f..b2cde8d6fe8 100644 --- a/cpp/ql/src/Critical/LoopBounds.qll +++ b/cpp/ql/src/Critical/LoopBounds.qll @@ -2,12 +2,24 @@ import cpp +/** + * An assignment to a variable with the value `0`. For example: + * ``` + * int x; + * x = 0; + * ``` + * but not: + * ``` + * int x = 0; + * ``` + */ class ZeroAssignment extends AssignExpr { ZeroAssignment() { this.getAnOperand() instanceof VariableAccess and this.getAnOperand() instanceof Zero } + /** Gets a variable that is assigned the value `0`. */ Variable assignedVariable() { result.getAnAccess() = this.getAnOperand() } } diff --git a/cpp/ql/src/Critical/MemoryFreed.qll b/cpp/ql/src/Critical/MemoryFreed.qll index 880199e54c9..44557503e43 100644 --- a/cpp/ql/src/Critical/MemoryFreed.qll +++ b/cpp/ql/src/Critical/MemoryFreed.qll @@ -9,10 +9,19 @@ private predicate freed(Expr e) { ) } +/** An expression that might be deallocated. */ class FreedExpr extends PointsToExpr { FreedExpr() { freed(this) } override predicate interesting() { freed(this) } } +/** + * An allocation expression that might be deallocated. For example: + * ``` + * int* p = new int; + * ... + * delete p; + * ``` + */ predicate allocMayBeFreed(AllocationExpr alloc) { anythingPointsTo(alloc) } diff --git a/cpp/ql/src/Critical/Negativity.qll b/cpp/ql/src/Critical/Negativity.qll index 161fe234967..e9c0a3d2410 100644 --- a/cpp/ql/src/Critical/Negativity.qll +++ b/cpp/ql/src/Critical/Negativity.qll @@ -1,10 +1,19 @@ import cpp +/** + * Holds if `val` is an access to the variable `v`, or if `val` + * is an assignment with an access to `v` on the left-hand side. + */ predicate valueOfVar(Variable v, Expr val) { val = v.getAnAccess() or val.(AssignExpr).getLValue() = v.getAnAccess() } +/** + * Holds if either: + * - `cond` is an (in)equality expression that compares the variable `v` to the value `-1`, or + * - `cond` is a relational expression that compares the variable `v` to a constant. + */ predicate boundsCheckExpr(Variable v, Expr cond) { exists(EQExpr eq | cond = eq and @@ -43,6 +52,18 @@ predicate boundsCheckExpr(Variable v, Expr cond) { ) } +/** + * Holds if `node` is an expression in a conditional statement and `succ` is an + * immediate successor of `node` that may be reached after evaluating `node`. + * For example, given + * ``` + * if (a < 10 && b) func1(); + * else func2(); + * ``` + * this predicate holds when either: + * - `node` is `a < 10` and `succ` is `func2()` or `b`, or + * - `node` is `b` and `succ` is `func1()` or `func2()` + */ predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) { if node.isCondition() then succ = node.getATrueSuccessor() or succ = node.getAFalseSuccessor() @@ -52,6 +73,12 @@ predicate conditionalSuccessor(ControlFlowNode node, ControlFlowNode succ) { ) } +/** + * Holds if the current value of the variable `v` at control-flow + * node `n` has been used either in: + * - an (in)equality comparison with the value `-1`, or + * - a relational comparison that compares `v` to a constant. + */ predicate boundsChecked(Variable v, ControlFlowNode node) { exists(Expr test | boundsCheckExpr(v, test) and @@ -63,6 +90,14 @@ predicate boundsChecked(Variable v, ControlFlowNode node) { ) } +/** + * Holds if `cond` compares `v` to some common error values. Specifically, this + * predicate holds when: + * - `cond` checks that `v` is equal to `-1`, or + * - `cond` checks that `v` is less than `0`, or + * - `cond` checks that `v` is less than or equal to `-1`, or + * - `cond` checks that `v` is not some common success value (see `successCondition`). + */ predicate errorCondition(Variable v, Expr cond) { exists(EQExpr eq | cond = eq and @@ -88,6 +123,14 @@ predicate errorCondition(Variable v, Expr cond) { ) } +/** + * Holds if `cond` compares `v` to some common success values. Specifically, this + * predicate holds when: + * - `cond` checks that `v` is not equal to `-1`, or + * - `cond` checks that `v` is greater than or equal than `0`, or + * - `cond` checks that `v` is greater than `-1`, or + * - `cond` checks that `v` is not some common error value (see `errorCondition`). + */ predicate successCondition(Variable v, Expr cond) { exists(NEExpr ne | cond = ne and @@ -113,6 +156,11 @@ predicate successCondition(Variable v, Expr cond) { ) } +/** + * Holds if there exists a comparison operation that checks whether `v` + * represents some common *error* values, and `n` may be reached + * immediately following the comparison operation. + */ predicate errorSuccessor(Variable v, ControlFlowNode n) { exists(Expr cond | errorCondition(v, cond) and n = cond.getATrueSuccessor() @@ -121,6 +169,11 @@ predicate errorSuccessor(Variable v, ControlFlowNode n) { ) } +/** + * Holds if there exists a comparison operation that checks whether `v` + * represents some common *success* values, and `n` may be reached + * immediately following the comparison operation. + */ predicate successSuccessor(Variable v, ControlFlowNode n) { exists(Expr cond | successCondition(v, cond) and n = cond.getATrueSuccessor() @@ -129,6 +182,10 @@ predicate successSuccessor(Variable v, ControlFlowNode n) { ) } +/** + * Holds if the current value of the variable `v` at control-flow node + * `n` may have been checked against a common set of *error* values. + */ predicate checkedError(Variable v, ControlFlowNode n) { errorSuccessor(v, n) or @@ -139,6 +196,10 @@ predicate checkedError(Variable v, ControlFlowNode n) { ) } +/** + * Holds if the current value of the variable `v` at control-flow node + * `n` may have been checked against a common set of *success* values. + */ predicate checkedSuccess(Variable v, ControlFlowNode n) { successSuccessor(v, n) or 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/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql b/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql index 72852f0b86c..965bb8440b0 100644 --- a/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql +++ b/cpp/ql/src/JPL_C/LOC-3/Rule 17/BasicIntTypes.ql @@ -30,7 +30,7 @@ predicate allowedTypedefs(TypedefType t) { * Gets a type which appears literally in the declaration of `d`. */ Type getAnImmediateUsedType(Declaration d) { - d.isDefined() and + d.hasDefinition() and ( result = d.(Function).getType() or result = d.(Variable).getType() 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/MistypedFunctionArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll index 39b4f5902da..2dced5d8d84 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qll @@ -6,6 +6,7 @@ import cpp +pragma[inline] private predicate arithTypesMatch(Type arg, Type parm) { arg = parm or 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/Options.qll b/cpp/ql/src/Options.qll index 353d012e339..3c7e320dff6 100644 --- a/cpp/ql/src/Options.qll +++ b/cpp/ql/src/Options.qll @@ -4,7 +4,7 @@ * * By default they fall back to the reasonable defaults provided in * `DefaultOptions.qll`, but by modifying this file, you can customize - * the standard Semmle analyses to give better results for your project. + * the standard analyses to give better results for your project. */ import cpp diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql index 2ed95e6cb55..54c6d1e7a96 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql @@ -15,31 +15,31 @@ import cpp import semmle.code.cpp.security.TaintTracking import TaintedWithPath -predicate taintedChild(Expr e, Expr tainted) { - ( - isAllocationExpr(e) - or - any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e - ) and - tainted = e.getAChild() and +/** + * Holds if `alloc` is an allocation, and `tainted` is a child of it that is a + * taint sink. + */ +predicate allocSink(Expr alloc, Expr tainted) { + isAllocationExpr(alloc) and + tainted = alloc.getAChild() and tainted.getUnspecifiedType() instanceof IntegralType } class TaintedAllocationSizeConfiguration extends TaintTrackingConfiguration { - override predicate isSink(Element tainted) { taintedChild(_, tainted) } + override predicate isSink(Element tainted) { allocSink(_, tainted) } } predicate taintedAllocSize( - Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause + Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause ) { isUserInput(source, taintCause) and exists(Expr tainted | - taintedChild(e, tainted) and + allocSink(alloc, tainted) and taintedWithPath(source, tainted, sourceNode, sinkNode) ) } -from Expr e, Expr source, PathNode sourceNode, PathNode sinkNode, string taintCause -where taintedAllocSize(e, source, sourceNode, sinkNode, taintCause) -select e, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow", +from Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause +where taintedAllocSize(source, alloc, sourceNode, sinkNode, taintCause) +select alloc, sourceNode, sinkNode, "This allocation size is derived from $@ and might overflow", source, "user input (" + taintCause + ")" diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index a10e3df0bdd..c5285fdac57 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -198,12 +198,12 @@ class InitializationFunction extends Function { ) or // If we have no definition, we look at SAL annotations - not this.isDefined() and + not this.hasDefinition() and this.getParameter(i).(SALParameter).isOut() and evidence = SuggestiveSALAnnotation() or // We have some external information that this function conditionally initializes - not this.isDefined() and + not this.hasDefinition() and any(ValidatedExternalCondInitFunction vc).isExternallyVerified(this, i) and evidence = ExternalEvidence() } @@ -406,7 +406,7 @@ class ConditionalInitializationFunction extends InitializationFunction { * Explicitly ignore pure virtual functions. */ - this.isDefined() and + this.hasDefinition() and this.paramNotReassignedAt(this, i, c) and not this instanceof PureVirtualFunction ) @@ -616,11 +616,11 @@ private predicate functionSignature(Function f, string qualifiedName, string typ * are never statically linked together. */ private Function getAPossibleDefinition(Function undefinedFunction) { - not undefinedFunction.isDefined() and + not undefinedFunction.hasDefinition() and exists(string qn, string typeSig | functionSignature(undefinedFunction, qn, typeSig) and functionSignature(result, qn, typeSig) ) and - result.isDefined() + result.hasDefinition() } /** @@ -631,7 +631,7 @@ private Function getAPossibleDefinition(Function undefinedFunction) { */ private Function getTarget1(Call c) { result = VirtualDispatch::getAViableTarget(c) and - result.isDefined() + result.hasDefinition() } /** diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql index 7cc00c05379..d49eef4202a 100644 --- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql +++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScaling.ql @@ -21,7 +21,7 @@ where destBase = baseType(destType) and destBase.getSize() != sourceBase.getSize() and not dest.isInMacroExpansion() and - // If the source type is a char* or void* then don't + // If the source type is a `char*` or `void*` then don't // produce a result, because it is likely to be a false // positive. not sourceBase instanceof CharType and diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql index f96598edd9e..d333a2b37bc 100644 --- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql +++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingChar.ql @@ -21,7 +21,7 @@ where destBase = baseType(destType) and destBase.getSize() != sourceBase.getSize() and not dest.isInMacroExpansion() and - // If the source type is a char* or void* then don't + // If the source type is a `char*` or `void*` then don't // produce a result, because it is likely to be a false // positive. not sourceBase instanceof CharType and diff --git a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql index 692325ff373..d356ba7bbc4 100644 --- a/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql +++ b/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql @@ -24,9 +24,9 @@ private predicate isCharSzPtrExpr(Expr e) { from Expr sizeofExpr, Expr e where // If we see an addWithSizeof then we expect the type of - // the pointer expression to be char* or void*. Otherwise it + // the pointer expression to be `char*` or `void*`. Otherwise it // is probably a mistake. addWithSizeof(e, sizeofExpr, _) and not isCharSzPtrExpr(e) select sizeofExpr, - "Suspicious sizeof offset in a pointer arithmetic expression. " + "The type of the pointer is " + - e.getFullyConverted().getType().toString() + "." + "Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@.", + e.getFullyConverted().getType() as t, t.toString() 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 new file mode 100644 index 00000000000..8388511932e --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll @@ -0,0 +1,282 @@ +/** + * Provides precise tracking of how big the memory pointed to by pointers is. + * For each pointer, we start tracking (starting from the allocation or an array declaration) + * 1) how long is the chunk of memory allocated + * 2) where the current pointer is in this chunk of memory + * As computing this information is obviously not possible for all pointers, + * we do not guarantee the existence of length/offset information for all pointers. + * However, when it exists it is guaranteed to be accurate. + * + * The length and offset are tracked in a similar way to the Rangeanalysis. + * Each length is a `ValueNumber + delta`, and each Offset is an `Operand + delta`. + * We choose to track a `ValueNumber` for length, because the Rangeanalysis offers + * integer bounds on instructions and operands in terms of `ValueNumber`s, + * and `Operand` for offset because integer bounds on `Operand`s are + * tighter than bounds on `Instruction`s. + */ + +import cpp +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 newtype TLength = + TZeroLength() or + TVNLength(ValueNumber vn) { + not vn.getAnInstruction() instanceof ConstantInstruction and + exists(Instruction i | + vn.getAnInstruction() = i and + ( + i.getResultIRType() instanceof IRSignedIntegerType or + i.getResultIRType() instanceof IRUnsignedIntegerType + ) + | + i instanceof PhiInstruction + or + i instanceof InitializeParameterInstruction + or + i instanceof CallInstruction + or + i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction + or + i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction + or + i.getAUse() instanceof ArgumentOperand + ) + } + +/** + * Array lengths are represented in a ValueNumber | Zero + delta format. + * This class keeps track of the ValueNumber or Zero. + * The delta is tracked in the predicate `knownArrayLength`. + */ +class Length extends TLength { + string toString() { none() } // overridden in subclasses +} + +/** + * This length class corresponds to an array having a constant length + * that is tracked by the delta value. + */ +class ZeroLength extends Length, TZeroLength { + override string toString() { result = "ZeroLength" } +} + +/** + * This length class corresponds to an array having variable length, i.e. the + * length is tracked by a value number. One example is an array having length + * `count` for an integer variable `count` in the program. + */ +class VNLength extends Length, TVNLength { + ValueNumber vn; + + VNLength() { this = TVNLength(vn) } + + /** Gets an instruction with this value number bound. */ + Instruction getInstruction() { this = TVNLength(valueNumber(result)) } + + ValueNumber getValueNumber() { result = vn } + + override string toString() { result = "VNLength(" + vn.getExampleInstruction().toString() + ")" } +} + +private newtype TOffset = + TZeroOffset() or + TOpOffset(Operand op) { + op.getAnyDef().getResultIRType() instanceof IRSignedIntegerType or + op.getAnyDef().getResultIRType() instanceof IRUnsignedIntegerType + } + +/** + * This class describes the offset of a pointer in a chunk of memory. + * It is either an `Operand` or zero, an additional integer delta is added later. + */ +class Offset extends TOffset { + string toString() { none() } // overridden in subclasses +} + +/** + * This class represents a fixed offset, only specified by a delta. + */ +class ZeroOffset extends Offset, TZeroOffset { + override string toString() { result = "ZeroOffset" } +} + +/** + * This class represents an offset of an operand. + */ +class OpOffset extends Offset, TOpOffset { + Operand op; + + OpOffset() { this = TOpOffset(op) } + + Operand getOperand() { result = op } + + override string toString() { result = "OpOffset(" + op.getDef().toString() + ")" } +} + +private int getBaseSizeForPointerType(PointerType type) { result = type.getBaseType().getSize() } + +/** + * Holds if pointer `prev` that points at offset `prevOffset + prevOffsetDelta` + * steps to `array` that points to `offset + offsetDelta` in one step. + * This predicate does not contain any recursive steps. + */ +bindingset[prevOffset, prevOffsetDelta] +predicate simpleArrayLengthStep( + Instruction array, Offset offset, int offsetDelta, Instruction prev, Offset prevOffset, + int prevOffsetDelta +) { + // array assign + array.(CopyInstruction).getSourceValue() = prev and + offset = prevOffset and + offsetDelta = prevOffsetDelta + or + // pointer add with constant + array.(PointerAddInstruction).getLeft() = prev and + offset = prevOffset and + offsetDelta = prevOffsetDelta + getConstantValue(array.(PointerAddInstruction).getRight()) + or + // pointer add with variable + array.(PointerAddInstruction).getLeft() = prev and + prevOffset instanceof ZeroOffset and + offset.(OpOffset).getOperand() = array.(PointerAddInstruction).getRightOperand() and + offsetDelta = prevOffsetDelta and + not exists(getConstantValue(array.(PointerAddInstruction).getRight())) + or + // pointer sub with constant + array.(PointerSubInstruction).getLeft() = prev and + offset = prevOffset and + offsetDelta = prevOffsetDelta - getConstantValue(array.(PointerSubInstruction).getRight()) + or + // array to pointer decay + array.(ConvertInstruction).getUnary() = prev and + array.getConvertedResultExpression() instanceof ArrayToPointerConversion and + offset = prevOffset and + offsetDelta = prevOffsetDelta + or + // cast of pointer to pointer with the same element size + exists(PointerType fromTyp, PointerType toTyp | + array.(PtrToPtrCastInstruction).getUnary() = prev and + prev.getResultLanguageType().hasType(fromTyp, false) and + array.getResultLanguageType().hasType(toTyp, false) and + offset = prevOffset and + offsetDelta = prevOffsetDelta and + if fromTyp instanceof VoidPointerType + then getBaseSizeForPointerType(toTyp) = 1 + else ( + if toTyp instanceof VoidPointerType + then getBaseSizeForPointerType(fromTyp) = 1 + else getBaseSizeForPointerType(toTyp) = getBaseSizeForPointerType(fromTyp) + ) + ) +} + +/** + * Parses a `sizeExpr` of malloc into a variable part (`lengthExpr`) and an integer offset (`delta`). + */ +private predicate deconstructMallocSizeExpr(Expr sizeExpr, Expr lengthExpr, int delta) { + sizeExpr instanceof AddExpr and + exists(Expr constantExpr | + lengthExpr = sizeExpr.(AddExpr).getAnOperand() and + constantExpr = sizeExpr.(AddExpr).getAnOperand() and + lengthExpr != constantExpr and + delta = constantExpr.getValue().toInt() + ) + or + sizeExpr instanceof SubExpr and + exists(Expr constantExpr | + lengthExpr = sizeExpr.(SubExpr).getLeftOperand() and + constantExpr = sizeExpr.(SubExpr).getRightOperand() and + delta = -constantExpr.getValue().toInt() + ) +} + +/** + * Holds if the instruction `array` is a dynamic memory allocation of `length`+`delta` elements. + */ +private predicate allocation(Instruction array, Length length, int delta) { + exists(AllocationExpr alloc, Type ptrTyp | + array.getUnconvertedResultExpression() = alloc and + array.getResultLanguageType().hasType(ptrTyp, false) and + // ensure that we have the same type of the allocation and the pointer + ptrTyp.stripTopLevelSpecifiers().(PointerType).getBaseType().getUnspecifiedType() = + alloc.getAllocatedElementType().getUnspecifiedType() and + // ensure that the size multiplier of the allocation is the same as the + // size of the type we are allocating + alloc.getSizeMult() = getBaseSizeForPointerType(ptrTyp) and + ( + length instanceof ZeroLength and + delta = alloc.getSizeExpr().getValue().toInt() + or + not exists(alloc.getSizeExpr().getValue().toInt()) and + ( + exists(Expr lengthExpr | + deconstructMallocSizeExpr(alloc.getSizeExpr(), lengthExpr, delta) and + length.(VNLength).getInstruction().getConvertedResultExpression() = lengthExpr + ) + or + not exists(int d | deconstructMallocSizeExpr(alloc.getSizeExpr(), _, d)) and + length.(VNLength).getInstruction().getConvertedResultExpression() = alloc.getSizeExpr() and + delta = 0 + ) + ) + ) +} + +/** + * Holds if `array` is declared as an array with length `length + lengthDelta` + */ +private predicate arrayDeclaration(Instruction array, Length length, int lengthDelta) { + ( + array instanceof VariableAddressInstruction or + array instanceof FieldAddressInstruction + ) and + exists(ArrayType type | array.getResultLanguageType().hasType(type, _) | + length instanceof ZeroLength and + lengthDelta = type.getArraySize() + ) +} + +/** + * Holds if `array` is declared as an array or allocated + * with length `length + lengthDelta` + */ +predicate arrayAllocationOrDeclaration(Instruction array, Length length, int lengthDelta) { + allocation(array, length, lengthDelta) + or + // declaration of variable of array type + arrayDeclaration(array, length, lengthDelta) +} + +/** + * Holds if the instruction `array` represents a pointer to a chunk of memory that holds + * `length + lengthDelta` elements, using only local analysis. + * `array` points at `offset + offsetDelta` in the chunk of memory. + * The pointer is in-bounds if `offset + offsetDelta < length + lengthDelta` and + * `offset + offsetDelta >= 0` holds. + * The pointer is out-of-bounds if `offset + offsetDelta >= length + lengthDelta` + * or `offset + offsetDelta < 0` holds. + * All pointers in this predicate are guaranteed to be non-null, + * but are not guaranteed to be live. + */ +predicate knownArrayLength( + Instruction array, Length length, int lengthDelta, Offset offset, int offsetDelta +) { + arrayAllocationOrDeclaration(array, length, lengthDelta) and + offset instanceof ZeroOffset and + offsetDelta = 0 + or + // simple step (no phi nodes) + exists(Instruction prev, Offset prevOffset, int prevOffsetDelta | + knownArrayLength(prev, length, lengthDelta, prevOffset, prevOffsetDelta) and + simpleArrayLengthStep(array, offset, offsetDelta, prev, prevOffset, prevOffsetDelta) + ) + or + // merge control flow after phi node - but only if all the bounds agree + forex(Instruction input | array.(PhiInstruction).getAnInput() = input | + knownArrayLength(input, length, lengthDelta, offset, offsetDelta) + ) +} 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..94227a5a8ac --- /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 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/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/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 67a2d11ff24..11ebef3e5ff 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 @@ -458,6 +462,15 @@ class Class extends UserType { exists(ClassDerivation d | d.getDerivedClass() = this and d = result) } + /** + * Gets class derivation number `index` of this class/struct, for example the + * `public B` is derivation 1 in the following code: + * ``` + * class D : public A, public B, public C { + * ... + * }; + * ``` + */ ClassDerivation getDerivation(int index) { exists(ClassDerivation d | d.getDerivedClass() = this and d.getIndex() = index and d = result) } @@ -900,6 +913,22 @@ class AbstractClass extends Class { class TemplateClass extends Class { TemplateClass() { usertypes(underlyingElement(this), _, 6) } + /** + * Gets a class instantiated from this template. + * + * For example for `MyTemplateClass` in the following code, the results are + * `MyTemplateClass` and `MyTemplateClass`: + * ``` + * template + * class MyTemplateClass { + * ... + * }; + * + * MyTemplateClass instance; + * + * MyTemplateClass instance; + * ``` + */ Class getAnInstantiation() { result.isConstructedFrom(this) and exists(result.getATemplateArgument()) diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll index e517f8e7b0e..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 @@ -13,8 +17,20 @@ class Comment extends Locatable, @comment { override Location getLocation() { comments(underlyingElement(this), _, result) } + /** + * Gets the text of this comment, including the opening `//` or `/*`, and the closing `*``/` if + * present. + */ string getContents() { comments(underlyingElement(this), result, _) } + /** + * Gets the AST element this comment is associated with. For example, the comment in the + * following code is associated with the declaration of `j`. + * ``` + * int i; + * int j; // Comment on j + * ``` + */ Element getCommentedElement() { commentbinding(underlyingElement(this), unresolveElement(result)) } diff --git a/cpp/ql/src/semmle/code/cpp/Compilation.qll b/cpp/ql/src/semmle/code/cpp/Compilation.qll index 02d962844c8..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 /* @@ -21,9 +25,9 @@ private predicate idOf(@compilation x, int y) = equivalenceRelation(id/2)(x, y) * Three things happen to each file during a compilation: * * 1. The file is compiled by a real compiler, such as gcc or VC. - * 2. The file is parsed by Semmle's C++ front-end. + * 2. The file is parsed by the CodeQL C++ front-end. * 3. The parsed representation is converted to database tables by - * Semmle's extractor. + * the CodeQL extractor. * * This class provides CPU and elapsed time information for steps 2 and 3, * but not for step 1. @@ -40,6 +44,7 @@ class Compilation extends @compilation { /** Gets a file compiled during this invocation. */ File getAFileCompiled() { result = getFileCompiled(_) } + /** Gets the `i`th file compiled during this invocation */ File getFileCompiled(int i) { compilation_compiling_files(this, i, unresolveElement(result)) } /** diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 1d5603fe4f4..6245005fd41 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 @@ -25,7 +29,7 @@ private import semmle.code.cpp.internal.QualifiedName as Q * `DeclarationEntry`, because they always have a unique source location. * `EnumConstant` and `FriendDecl` are both examples of this. */ -abstract class Declaration extends Locatable, @declaration { +class Declaration extends Locatable, @declaration { /** * Gets the innermost namespace which contains this declaration. * @@ -98,7 +102,12 @@ abstract 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. @@ -161,6 +170,7 @@ abstract class Declaration extends Locatable, @declaration { /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } + /** DEPRECATED: Use `hasDefinition` instead. */ predicate isDefined() { hasDefinition() } /** Gets the preferred location of this declaration, if any. */ @@ -303,7 +313,7 @@ abstract class DeclarationEntry extends Locatable { * available), or the name declared by this entry otherwise. */ string getCanonicalName() { - if getDeclaration().isDefined() + if getDeclaration().hasDefinition() then result = getDeclaration().getDefinition().getName() else result = getName() } diff --git a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll index f03f03783c1..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. */ @@ -11,6 +15,7 @@ class Diagnostic extends Locatable, @diagnostic { /** Gets the error code for this compiler message. */ string getTag() { diagnostics(underlyingElement(this), _, result, _, _, _) } + /** Holds if `s` is the error code for this compiler message. */ predicate hasTag(string s) { this.getTag() = s } /** diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 2b236147484..50b72037ff7 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 @@ -261,8 +266,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..2c51a5228d9 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,6 +23,17 @@ 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, _, _, _) } diff --git a/cpp/ql/src/semmle/code/cpp/Field.qll b/cpp/ql/src/semmle/code/cpp/Field.qll index eb864a16063..79c9b58dfea 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 diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 60ef2d587ef..061e79c7d45 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 @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll index c788ea70058..e0a6b04b1fc 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 diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 9ed4b27f562..979e94c2061 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with functions, including template functions. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Member import semmle.code.cpp.Class @@ -103,6 +107,9 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { /** * Holds if this function is declared to be `constexpr`. + * + * Note that this does not hold if the function has been declared + * `consteval`. */ predicate isDeclaredConstexpr() { this.hasSpecifier("declared_constexpr") } @@ -115,9 +122,16 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * template constexpr int g(T x) { return f(x); } * ``` * `g` is declared constexpr, but is not constexpr. + * + * Will also hold if this function is `consteval`. */ predicate isConstexpr() { this.hasSpecifier("is_constexpr") } + /** + * Holds if this function is declared to be `consteval`. + */ + predicate isConsteval() { this.hasSpecifier("is_consteval") } + /** * Holds if this function is declared with `__attribute__((naked))` or * `__declspec(naked)`. @@ -174,17 +188,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. */ @@ -606,18 +611,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) } /** @@ -707,427 +702,6 @@ class TopLevelFunction extends Function { 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() } -} - /** * A C++ user-defined operator [N4140 13.5]. */ @@ -1139,64 +713,6 @@ class Operator extends Function { } } -/** - * 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: 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/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll new file mode 100644 index 00000000000..0ccc63196ae --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -0,0 +1,487 @@ +/** + * 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 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 { + /** 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 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() } +} + +/** + * 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" } +} diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..9b9b12aaef0 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -79,7 +79,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 +107,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 @@ -130,7 +133,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { /** * 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 +153,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 +172,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 +207,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/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 1fbd8b0f071..91957f2d498 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -165,6 +165,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/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 38e5efba6df..55eb4f27d3d 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -376,6 +376,8 @@ private predicate isIntegralType(@builtintype type, int kind) { kind = 43 or kind = 44 + or + kind = 51 ) } @@ -463,6 +465,8 @@ private predicate integralTypeMapping(int original, int canonical, int unsigned, original = 43 and canonical = 43 and unsigned = -1 and signed = -1 // char16_t or original = 44 and canonical = 44 and unsigned = -1 and signed = -1 // char32_t + or + original = 51 and canonical = 51 and unsigned = -1 and signed = -1 // char8_t } /** @@ -697,28 +701,188 @@ class Int128Type extends IntegralType { override string getCanonicalQLClass() { result = "Int128Type" } } +private newtype TTypeDomain = + TRealDomain() or + TComplexDomain() or + TImaginaryDomain() + /** - * The C/C++ floating point types. See 4.5. This includes `float`, - * `double` and `long double` types. - * ``` - * float f; - * double d; - * long double ld; - * ``` + * The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or + * `ImaginaryDomain`. + */ +class TypeDomain extends TTypeDomain { + /** Gets a textual representation of this type domain. */ + string toString() { none() } +} + +/** + * The type domain of a floating-point type that represents a real number. + */ +class RealDomain extends TypeDomain, TRealDomain { + final override string toString() { result = "real" } +} + +/** + * The type domain of a floating-point type that represents a complex number. + */ +class ComplexDomain extends TypeDomain, TComplexDomain { + final override string toString() { result = "complex" } +} + +/** + * The type domain of a floating-point type that represents an imaginary number. + */ +class ImaginaryDomain extends TypeDomain, TImaginaryDomain { + final override string toString() { result = "imaginary" } +} + +/** + * Data for floating-point types. + * + * kind: The original type kind. Can be any floating-point type kind. + * base: The numeric base of the number's representation. Can be 2 (binary) or 10 (decimal). + * domain: The type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`. + * realKind: The type kind of the corresponding real type. For example, the corresponding real type + * of `_Complex double` is `double`. + * extended: `true` if the number is an extended-precision floating-point number, such as + * `_Float32x`. + */ +private predicate floatingPointTypeMapping( + int kind, int base, TTypeDomain domain, int realKind, boolean extended +) { + // float + kind = 24 and base = 2 and domain = TRealDomain() and realKind = 24 and extended = false + or + // double + kind = 25 and base = 2 and domain = TRealDomain() and realKind = 25 and extended = false + or + // long double + kind = 26 and base = 2 and domain = TRealDomain() and realKind = 26 and extended = false + or + // _Complex float + kind = 27 and base = 2 and domain = TComplexDomain() and realKind = 24 and extended = false + or + // _Complex double + kind = 28 and base = 2 and domain = TComplexDomain() and realKind = 25 and extended = false + or + // _Complex long double + kind = 29 and base = 2 and domain = TComplexDomain() and realKind = 26 and extended = false + or + // _Imaginary float + kind = 30 and base = 2 and domain = TImaginaryDomain() and realKind = 24 and extended = false + or + // _Imaginary double + kind = 31 and base = 2 and domain = TImaginaryDomain() and realKind = 25 and extended = false + or + // _Imaginary long double + kind = 32 and base = 2 and domain = TImaginaryDomain() and realKind = 26 and extended = false + or + // __float128 + kind = 38 and base = 2 and domain = TRealDomain() and realKind = 38 and extended = false + or + // _Complex __float128 + kind = 39 and base = 2 and domain = TComplexDomain() and realKind = 38 and extended = false + or + // _Decimal32 + kind = 40 and base = 10 and domain = TRealDomain() and realKind = 40 and extended = false + or + // _Decimal64 + kind = 41 and base = 10 and domain = TRealDomain() and realKind = 41 and extended = false + or + // _Decimal128 + kind = 42 and base = 10 and domain = TRealDomain() and realKind = 42 and extended = false + or + // _Float32 + kind = 45 and base = 2 and domain = TRealDomain() and realKind = 45 and extended = false + or + // _Float32x + kind = 46 and base = 2 and domain = TRealDomain() and realKind = 46 and extended = true + or + // _Float64 + kind = 47 and base = 2 and domain = TRealDomain() and realKind = 47 and extended = false + or + // _Float64x + kind = 48 and base = 2 and domain = TRealDomain() and realKind = 48 and extended = true + or + // _Float128 + kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false + or + // _Float128x + kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true +} + +/** + * The C/C++ floating point types. See 4.5. This includes `float`, `double` and `long double`, the + * fixed-size floating-point types like `_Float32`, the extended-precision floating-point types like + * `_Float64x`, and the decimal floating-point types like `_Decimal32`. It also includes the complex + * and imaginary versions of all of these types. */ class FloatingPointType extends ArithmeticType { + final int base; + final TypeDomain domain; + final int realKind; + final boolean extended; + FloatingPointType() { exists(int kind | builtintypes(underlyingElement(this), _, kind, _, _, _) and - ( - kind >= 24 and kind <= 32 - or - kind >= 38 and kind <= 42 - or - kind >= 45 and kind <= 50 - ) + floatingPointTypeMapping(kind, base, domain, realKind, extended) ) } + + /** Gets the numeric base of this type's representation: 2 (binary) or 10 (decimal). */ + final int getBase() { result = base } + + /** + * Gets the type domain of this type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`. + */ + final TypeDomain getDomain() { result = domain } + + /** + * Gets the corresponding real type of this type. For example, the corresponding real type of + * `_Complex double` is `double`. + */ + final RealNumberType getRealType() { + builtintypes(unresolveElement(result), _, realKind, _, _, _) + } + + /** Holds if this type is an extended precision floating-point type, such as `_Float32x`. */ + final predicate isExtendedPrecision() { extended = true } +} + +/** + * A floating-point type representing a real number. + */ +class RealNumberType extends FloatingPointType { + RealNumberType() { domain instanceof RealDomain } +} + +/** + * A floating-point type representing a complex number. + */ +class ComplexNumberType extends FloatingPointType { + ComplexNumberType() { domain instanceof ComplexDomain } +} + +/** + * A floating-point type representing an imaginary number. + */ +class ImaginaryNumberType extends FloatingPointType { + ImaginaryNumberType() { domain instanceof ImaginaryDomain } +} + +/** + * A floating-point type whose representation is base 2. + */ +class BinaryFloatingPointType extends FloatingPointType { + BinaryFloatingPointType() { base = 2 } +} + +/** + * A floating-point type whose representation is base 10. + */ +class DecimalFloatingPointType extends FloatingPointType { + DecimalFloatingPointType() { base = 10 } } /** @@ -727,7 +891,7 @@ class FloatingPointType extends ArithmeticType { * float f; * ``` */ -class FloatType extends FloatingPointType { +class FloatType extends RealNumberType, BinaryFloatingPointType { FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) } override string getCanonicalQLClass() { result = "FloatType" } @@ -739,7 +903,7 @@ class FloatType extends FloatingPointType { * double d; * ``` */ -class DoubleType extends FloatingPointType { +class DoubleType extends RealNumberType, BinaryFloatingPointType { DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) } override string getCanonicalQLClass() { result = "DoubleType" } @@ -751,7 +915,7 @@ class DoubleType extends FloatingPointType { * long double ld; * ``` */ -class LongDoubleType extends FloatingPointType { +class LongDoubleType extends RealNumberType, BinaryFloatingPointType { LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) } override string getCanonicalQLClass() { result = "LongDoubleType" } @@ -763,7 +927,7 @@ class LongDoubleType extends FloatingPointType { * __float128 f128; * ``` */ -class Float128Type extends FloatingPointType { +class Float128Type extends RealNumberType, BinaryFloatingPointType { Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) } override string getCanonicalQLClass() { result = "Float128Type" } @@ -775,7 +939,7 @@ class Float128Type extends FloatingPointType { * _Decimal32 d32; * ``` */ -class Decimal32Type extends FloatingPointType { +class Decimal32Type extends RealNumberType, DecimalFloatingPointType { Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) } override string getCanonicalQLClass() { result = "Decimal32Type" } @@ -787,7 +951,7 @@ class Decimal32Type extends FloatingPointType { * _Decimal64 d64; * ``` */ -class Decimal64Type extends FloatingPointType { +class Decimal64Type extends RealNumberType, DecimalFloatingPointType { Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) } override string getCanonicalQLClass() { result = "Decimal64Type" } @@ -799,7 +963,7 @@ class Decimal64Type extends FloatingPointType { * _Decimal128 d128; * ``` */ -class Decimal128Type extends FloatingPointType { +class Decimal128Type extends RealNumberType, DecimalFloatingPointType { Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) } override string getCanonicalQLClass() { result = "Decimal128Type" } @@ -833,6 +997,18 @@ class WideCharType extends IntegralType { override string getCanonicalQLClass() { result = "WideCharType" } } +/** + * The C/C++ `char8_t` type. This is available starting with C++20. + * ``` + * char8_t c8; + * ``` + */ +class Char8Type extends IntegralType { + Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) } + + override string getCanonicalQLClass() { result = "Char8Type" } +} + /** * The C/C++ `char16_t` type. This is available starting with C11 and C++11. * ``` diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index cbb7f39adbd..4484cde84de 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -38,7 +38,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ override Specifier getASpecifier() { result = Type.super.getASpecifier() } override Location getLocation() { - if isDefined() + if hasDefinition() then result = this.getDefinitionLocation() else result = this.getADeclarationLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index a4bbbdbb9ab..54f39ab2bb6 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -126,10 +126,7 @@ class Variable extends Declaration, @variable { or exists(AssignExpr ae | ae.getLValue().(Access).getTarget() = this and result = ae.getRValue()) or - exists(AggregateLiteral l | - this.getDeclaringType() = l.getType() and - result = l.getChild(this.(Field).getInitializationOrder()) - ) + exists(ClassAggregateLiteral l | result = l.getFieldExpr(this)) } /** @@ -263,24 +260,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() } /** 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/Assertions.qll b/cpp/ql/src/semmle/code/cpp/commons/Assertions.qll index a4d3669d2ea..9d466387fff 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Assertions.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Assertions.qll @@ -12,12 +12,12 @@ abstract class Assertion extends Locatable { } /** - * A libc assert, as defined in assert.h. A macro with the head - * "assert(expr)" that expands to a conditional expression which - * may terminate the program. + * A libc assert, as defined in assert.h. A macro with a head + * that matches the prefix "assert(", and expands to a conditional + * expression which may terminate the program. */ class LibcAssert extends MacroInvocation, Assertion { - LibcAssert() { this.getMacro().getHead() = "assert(expr)" } + LibcAssert() { this.getMacro().getHead().matches("assert(%") } override Expr getAsserted() { exists(ConditionalExpr ce | this.getAGeneratedElement() = ce | result = ce.getCondition()) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll b/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll index c884038a1c8..88e6a48ff55 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Buffer.qll @@ -92,13 +92,7 @@ int getBufferSize(Expr bufferExpr, Element why) { // dataflow (all sources must be the same size) bufferExprNode = DataFlow::exprNode(bufferExpr) and result = - min(Expr def | - DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode) - | - getBufferSize(def, _) - ) and - result = - max(Expr def | + unique(Expr def | DataFlow::localFlowStep(DataFlow::exprNode(def), bufferExprNode) | getBufferSize(def, _) 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/controlflow/internal/ConstantExprs.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll index f0af3d219b5..c473f156088 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll @@ -532,13 +532,7 @@ library class ExprEvaluator extends int { interestingVariableAccess(e, va, v, true) and // All assignments must have the same int value result = - min(Expr value | - value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value) - | - getValueInternalNonSubExpr(value) - ) and - result = - max(Expr value | + unique(Expr value | value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value) | getValueInternalNonSubExpr(value) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 8a99a71f6af..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 @@ -166,10 +183,14 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) ) } -private predicate valueMayEscapeAt(Expr e) { +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 ) or exists(AssignExpr assign | e = assign.getRValue().getFullyConverted()) @@ -187,8 +208,8 @@ private predicate valueMayEscapeAt(Expr e) { exists(AsmStmt asm | e = asm.getAChild().(Expr).getFullyConverted()) } -private predicate valueMayEscapeMutablyAt(Expr e) { - valueMayEscapeAt(e) and +private predicate addressMayEscapeMutablyAt(Expr e) { + addressMayEscapeAt(e) and exists(Type t | t = e.getType().getUnderlyingType() | exists(PointerType pt | pt = t @@ -207,6 +228,22 @@ private predicate valueMayEscapeMutablyAt(Expr e) { ) } +private predicate lvalueMayEscapeAt(Expr e) { + // A call qualifier, like `q` in `q.f()`, is special in that the address of + // `q` escapes even though `q` is not a pointer or a reference. + exists(Call call | + e = call.getQualifier().getFullyConverted() and + e.getType().getUnspecifiedType() instanceof Class + ) +} + +private predicate lvalueMayEscapeMutablyAt(Expr e) { + lvalueMayEscapeAt(e) and + // A qualifier of a call to a const member function is converted to a const + // class type. + not e.getType().isConst() +} + private predicate addressFromVariableAccess(VariableAccess va, Expr e) { pointerFromVariableAccess(va, e) or @@ -253,8 +290,11 @@ private module EscapesTree_Cached { */ cached predicate variableAddressEscapesTree(VariableAccess va, Expr e) { - valueMayEscapeAt(e) and + addressMayEscapeAt(e) and addressFromVariableAccess(va, e) + or + lvalueMayEscapeAt(e) and + lvalueFromVariableAccess(va, e) } /** @@ -283,8 +323,11 @@ private module EscapesTree_Cached { */ cached predicate variableAddressEscapesTreeNonConst(VariableAccess va, Expr e) { - valueMayEscapeMutablyAt(e) and + addressMayEscapeMutablyAt(e) and addressFromVariableAccess(va, e) + or + lvalueMayEscapeMutablyAt(e) and + lvalueFromVariableAccess(va, e) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll b/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll index 626e50925f9..2d8b52f8622 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/RecursionPrevention.qll @@ -1,6 +1,6 @@ /** * DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in - * Semmle Core 1.17 and above. There is no need for this module because it's + * any supported tooling. There is no need for this module because it's * impossible to accidentally depend on recursion through * `DataFlow::Configuration` in current releases. * 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/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index a1daeb66411..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 783ac641e6e..1f42c21d5a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,167 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output 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. */ - cached 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), and `contentOut` describes the content of `node` that - * it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) 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 - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() + 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), read.getContainerType()) ) or - // store - exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) - ) - or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, read) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through `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), and - * `contentOut` describes the content of `out` that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } /** - * 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. + * 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. */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() + 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), and `contentOut` describes the content of the return - * node that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, read) and + kind = ret.getKind() + ) } } import Final } + /** + * 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(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and + containerType = getErasedNodeTypeBound(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 = getErasedNodeTypeBound(n1) and + containerType = getErasedNodeTypeBound(n2) + ) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,17 +367,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(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), TContentNone(), 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 @@ -520,6 +409,24 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + 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(TypedContent tc) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,26 +436,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 = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) +} -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()" } } /** @@ -678,6 +597,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 @@ -688,7 +619,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 { @@ -700,7 +631,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 { @@ -712,9 +645,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()) ) } @@ -779,77 +712,79 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** 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. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + private DataFlowType t; + + 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 { + private TypedContent tc; + + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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 a1daeb66411..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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..617559e195c 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() } } /** @@ -311,9 +293,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 700087871cc..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 @@ -43,7 +45,7 @@ class Node extends TNode { /** * INTERNAL: Do not use. Alternative name for `getFunction`. */ - Function getEnclosingCallable() { result = this.getFunction() } + final Function getEnclosingCallable() { result = unique(Function f | f = this.getFunction() | f) } /** Gets the type of this node. */ Type getType() { none() } // overridden in subclasses @@ -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,23 +276,32 @@ 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.getLocation() } + override Location getLocation() { result = pd.getActualLocation() } PartialDefinition getPartialDefinition() { result = pd } 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() } } /** @@ -496,8 +484,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { // Expr -> Expr exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr()) or - exprToExprStep_nocfg(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr(), nodeTo.asExpr()) - or // Node -> FlowVar -> VariableAccess exists(FlowVar var | ( @@ -520,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() + ) } /** @@ -657,7 +651,7 @@ private module FieldFlow { exists(FieldConfiguration cfg | cfg.hasFlow(node1, node2)) and // This configuration should not be able to cross function boundaries, but // we double-check here just to be sure. - node1.getFunction() = node2.getFunction() + node1.getEnclosingCallable() = node2.getEnclosingCallable() } } 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 2a2755ac1d0..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,44 +108,21 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - private newtype TPartialDefinition = - TExplicitFieldStoreQualifier(Expr qualifier, ControlFlowNode node) { - exists(FieldAccess fa | qualifier = fa.getQualifier() | - isInstanceFieldWrite(fa, node) - or - exists(PartialDefinition pd | - node = pd.getSubBasicBlockStart() and - fa = pd.getDefinedExpr() - ) - ) - } or - TExplicitCallQualifier(Expr qualifier) { - exists(Call call | - qualifier = call.getQualifier() and - not call.getTarget().hasSpecifier("const") - ) - } or - TReferenceArgument(Expr arg, VariableAccess va) { referenceArgument(va, arg) } - - private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) { - assignmentLikeOperation(node, _, fa, _) - } - - class PartialDefinition extends TPartialDefinition { - Expr definedExpr; + class PartialDefinition extends Expr { + Expr innerDefinedExpr; ControlFlowNode node; PartialDefinition() { - this = TExplicitFieldStoreQualifier(definedExpr, node) - or - this = TExplicitCallQualifier(definedExpr) and node = definedExpr - or - this = TReferenceArgument(definedExpr, node) + exists(Expr convertedInner | + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + not this instanceof Conversion + ) } - predicate partiallyDefines(Variable v) { definedExpr = v.getAnAccess() } + predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() } - predicate partiallyDefinesThis(ThisExpr e) { definedExpr = e } + predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } /** * Gets the subBasicBlock where this `PartialDefinition` is defined. @@ -158,69 +130,37 @@ 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 = definedExpr } - - Location getLocation() { - not exists(definedExpr.getLocation()) and result = definedExpr.getParent().getLocation() - or - definedExpr.getLocation() instanceof UnknownLocation and - result = definedExpr.getParent().getLocation() - or - result = definedExpr.getLocation() and not result instanceof UnknownLocation + predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this } - string toString() { result = "partial def of " + definedExpr } + /** + * Gets the location of this element, adjusted to avoid unknown locations + * on compiler-generated `ThisExpr`s. + */ + Location getActualLocation() { + not exists(this.getLocation()) and result = this.getParent().getLocation() + or + this.getLocation() instanceof UnknownLocation and + result = this.getParent().getLocation() + or + result = this.getLocation() and not result instanceof UnknownLocation + } } /** * A partial definition that's a definition by reference. */ - class DefinitionByReference extends PartialDefinition, TReferenceArgument { - VariableAccess va; - - DefinitionByReference() { - // `this` is not restricted in this charpred. That's because the full - // extent of this class includes the charpred of the superclass, which - // relates `this` to `definedExpr`, and `va` is functionally determined - // by `definedExpr`. - referenceArgument(va, definedExpr) - } - - 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() - ) - ) + class DefinitionByReference extends PartialDefinition { + DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } } @@ -337,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) { @@ -425,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) ) } @@ -450,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 @@ -463,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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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 f68eaef5d8b..fe467be6fe4 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -6,9 +6,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() } @@ -338,7 +342,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { * int myFunctionTarget(int); * * void myFunction() { - * int (*myFunctionPointer)(int) = &myTarget; + * int (*myFunctionPointer)(int) = &myFunctionTarget; * } * ``` */ diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 446bdbdee51..5729a49086b 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -4,7 +4,7 @@ import semmle.code.cpp.exprs.Expr * A C/C++ builtin operation. This is the root QL class encompassing * built-in functionality. */ -abstract class BuiltInOperation extends Expr { +class BuiltInOperation extends Expr, @builtin_op { override string getCanonicalQLClass() { result = "BuiltInOperation" } } @@ -12,17 +12,7 @@ abstract class BuiltInOperation extends Expr { * 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 diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 6eb4ed52319..abb26002091 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -9,9 +9,8 @@ private import semmle.code.cpp.dataflow.EscapesTree */ abstract class Call extends Expr, NameQualifiableElement { /** - * Gets the number of actual parameters in this call; use - * `getArgument(i)` with `i` between `0` and `result - 1` to - * retrieve actuals. + * Gets the number of arguments (actual parameters) of this call. The count + * does _not_ include the qualifier of the call, if any. */ int getNumberOfArguments() { result = count(this.getAnArgument()) } @@ -32,21 +31,24 @@ abstract class Call extends Expr, NameQualifiableElement { Expr getQualifier() { result = this.getChild(-1) } /** - * Gets an argument for this call. + * Gets an argument for this call. To get the qualifier of this call, if + * any, use `getQualifier()`. */ Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 0) } /** * Gets the nth argument for this call. * - * The range of `n` is from `0` to `getNumberOfArguments() - 1`. + * The range of `n` is from `0` to `getNumberOfArguments() - 1`. To get the + * qualifier of this call, if any, use `getQualifier()`. */ Expr getArgument(int n) { result = this.getChild(n) and n >= 0 } /** - * Gets a sub expression of the argument at position `index`. If the + * Gets a subexpression of the argument at position `index`. If the * argument itself contains calls, such calls will be considered - * leafs in the expression tree. + * leaves in the expression tree. The qualifier of the call, if any, is not + * considered to be an argument. * * Example: the call `f(2, 3 + 4, g(4 + 5))` has sub expression(s) * `2` at index 0; `3`, `4`, and `3 + 4` at index 1; and `g(4 + 5)` @@ -80,7 +82,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 @@ -99,11 +102,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 @@ -122,6 +129,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 } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 3a45d8597d5..a00014b9af7 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -7,7 +7,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 +34,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 +48,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 +62,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 @@ -699,7 +709,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 } } @@ -762,7 +772,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 } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index 97371919b02..fd15a22fbd2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -53,7 +53,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() { diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index f634d9239b3..4a5b1b21c8d 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -86,7 +86,7 @@ class Closure extends Class { result.getName() = "operator()" } - override string toString() { result = "decltype([...](...){...})" } + override string getDescription() { result = "decltype([...](...){...})" } } /** @@ -99,7 +99,7 @@ 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" } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index 211b65c809d..3360be330c2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -145,8 +145,6 @@ class HexLiteral extends Literal { /** * A C/C++ aggregate literal. - * - * For example: */ class AggregateLiteral extends Expr, @aggregateliteral { override string getCanonicalQLClass() { result = "AggregateLiteral" } 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/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/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..d8904625e0e 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 + ) } /** 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 a1daeb66411..1aeedf717f7 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 @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 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 @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 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 @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 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 @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 783ac641e6e..1f42c21d5a7 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 @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,167 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output 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. */ - cached 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), and `contentOut` describes the content of `node` that - * it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) 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 - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() + 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), read.getContainerType()) ) or - // store - exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) - ) - or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, read) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through `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), and - * `contentOut` describes the content of `out` that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } /** - * 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. + * 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. */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() + 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), and `contentOut` describes the content of the return - * node that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, read) and + kind = ret.getKind() + ) } } import Final } + /** + * 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(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and + containerType = getErasedNodeTypeBound(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 = getErasedNodeTypeBound(n1) and + containerType = getErasedNodeTypeBound(n2) + ) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,17 +367,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(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), TContentNone(), 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 @@ -520,6 +409,24 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + 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(TypedContent tc) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,26 +436,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 = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) +} -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()" } } /** @@ -678,6 +597,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 @@ -688,7 +619,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 { @@ -700,7 +631,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 { @@ -712,9 +645,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()) ) } @@ -779,77 +712,79 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** 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. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + private DataFlowType t; + + 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 { + private TypedContent tc; + + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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 c5cf4180765..ff809e0d3eb 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,32 @@ 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() } +private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { + exists(FieldAddressInstruction fa, StoreInstruction store | + store = node2.asInstruction() and + store.getDestinationAddress() = fa and + store.getSourceValue() = node1.asInstruction() and + f.(FieldContent).getField() = fa.getField() + ) +} - override Type getType() { none() } +private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { + exists(FieldAddressInstruction fa, StoreInstruction store | + node1.asInstruction() = store and + store.getDestinationAddress() = fa and + node2.asInstruction().(ChiInstruction).getPartial() = store and + f.(FieldContent).getField() = fa.getField() + ) } /** @@ -186,7 +208,8 @@ private class ArrayContent extends Content, TArrayContent { * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - none() // stub implementation + storeStepNoChi(node1, f, node2) or + storeStepChi(node1, f, node2) } /** @@ -195,7 +218,12 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { * `node2`. */ predicate readStep(Node node1, Content f, Node node2) { - none() // stub implementation + exists(FieldAddressInstruction fa, LoadInstruction load | + load.getSourceAddress() = fa and + node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and + fa.getField() = f.(FieldContent).getField() and + load = node2.asInstruction() + ) } /** @@ -270,3 +298,6 @@ predicate isImmutableOrUnobservable(Node n) { // complex to model here. any() } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } 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 193173da442..bee21b93cb0 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 @@ -54,8 +54,8 @@ 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. */ - Parameter asParameter() { result = this.(ParameterNode).getParameter() } + /** 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 @@ -63,6 +63,16 @@ class Node extends TIRDataFlowNode { */ Variable asVariable() { result = this.(VariableNode).getVariable() } + /** + * Gets the expression that is partially defined by this node, if any. + * + * Partial definitions are created for field stores (`x.y = taint();` is a partial + * definition of `x`), and for calls that may change the value of an object (so + * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is + * a partial definition of `&x`). + */ + Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() } + /** * DEPRECATED: See UninitializedNode. * @@ -96,6 +106,9 @@ class Node extends TIRDataFlowNode { string toString() { none() } // overridden by subclasses } +/** + * An instruction, viewed as a node in a data flow graph. + */ class InstructionNode extends Node, TInstructionNode { Instruction instr; @@ -142,30 +155,91 @@ class ExprNode extends InstructionNode { override string toString() { result = this.asConvertedExpr().toString() } } +/** + * INTERNAL: do not use. Translates a parameter/argument index into a negative + * number that denotes the index of its side effect (pointer indirection). + */ +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 { - override InitializeParameterInstruction instr; + 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 `c` at the specified (zero-based) - * position. The implicit `this` parameter is considered to have index `-1`. + * 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 i) { f.getParameter(i) = instr.getParameter() } + 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; + + ExplicitParameterNode() { exists(instr.getParameter()) } + + 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 InstructionNode { - override InitializeThisInstruction instr; +/** An implicit `this` parameter. */ +class ThisParameterNode extends ParameterNode { + override InitializeParameterInstruction instr; + + 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 @@ -204,6 +278,67 @@ abstract class PostUpdateNode extends InstructionNode { abstract Node getPreUpdateNode(); } +/** + * The base class for nodes that perform "partial definitions". + * + * In contrast to a normal "definition", which provides a new value for + * something, a partial definition is an expression that may affect a + * value, but does not necessarily replace it entirely. For example: + * ``` + * x.y = 1; // a partial definition of the object `x`. + * x.y.z = 1; // a partial definition of the object `x.y`. + * x.setY(1); // a partial definition of the object `x`. + * setY(&x); // a partial definition of the object `x`. + * ``` + */ +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { + abstract Expr getDefinedExpr(); +} + +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + FieldAddressInstruction field; + + ExplicitFieldStoreQualifierNode() { + not instr.isResultConflated() and + 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() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } +} + +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { + override StoreInstruction instr; + FieldAddressInstruction field; + + ExplicitSingleFieldStoreQualifierNode() { + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) + } + + override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } +} + /** * A node that represents the value of a variable after a function call that * may have changed the variable because it's passed by reference. @@ -252,6 +387,18 @@ 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 @@ -288,6 +435,10 @@ class VariableNode extends Node, TVariableNode { */ InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr } +/** + * Gets the `Node` corresponding to a definition by reference of the variable + * that is passed as `argument` of a call. + */ DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e } /** @@ -305,7 +456,7 @@ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e } /** * Gets the `Node` corresponding to the value of `p` at function entry. */ -ParameterNode parameterNode(Parameter p) { result.getParameter() = p } +ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p } /** Gets the `VariableNode` corresponding to the variable `v`. */ VariableNode variableNode(Variable v) { result.getVariable() = v } @@ -334,12 +485,46 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) } +pragma[noinline] +private predicate getFieldSizeOfClass(Class c, Type type, int size) { + exists(Field f | + f.getDeclaringType() = c and + f.getType() = type and + type.getSize() = size + ) +} + 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 @@ -360,6 +545,32 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + // 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; + // } + // ... + // setX(&p, taint()); + // ``` + // 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. + 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, Class cTo | + type = iFrom.getResultType() and + cTo = iTo.getResultType() and + cTo.getSize() = size and + getFieldSizeOfClass(cTo, type, size) + ) + or // Flow through modeled functions modelFlow(iFrom, iTo) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll new file mode 100644 index 00000000000..d1cafb28f1c --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/ModelUtil.qll @@ -0,0 +1,47 @@ +/** + * Provides predicates for mapping the `FunctionInput` and `FunctionOutput` + * classes used in function models to the corresponding instructions. + */ + +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow + +/** + * Gets the instruction that goes into `input` for `call`. + */ +Instruction callInput(CallInstruction call, FunctionInput input) { + // A positional argument + exists(int index | + result = call.getPositionalArgument(index) and + input.isParameter(index) + ) + or + // A value pointed to by a positional argument + exists(ReadSideEffectInstruction read | + result = read and + read.getPrimaryInstruction() = call and + input.isParameterDeref(read.getIndex()) + ) + or + // The qualifier pointer + result = call.getThisArgument() and + input.isQualifierAddress() + //TODO: qualifier deref +} + +/** + * Gets the instruction that holds the `output` for `call`. + */ +Instruction callOutput(CallInstruction call, FunctionOutput output) { + // The return value + result = call and + output.isReturnValue() + or + // The side effect of a call on the value pointed to by a positional argument + exists(WriteSideEffectInstruction effect | + result = effect and + effect.getPrimaryInstruction() = call and + output.isParameterDeref(effect.getIndex()) + ) + // TODO: qualifiers, return value dereference +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 8d7c9194f4f..2290bab0571 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -1,5 +1,8 @@ private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.DataFlow +private import ModelUtil +private import semmle.code.cpp.models.interfaces.DataFlow +private import semmle.code.cpp.models.interfaces.SideEffect /** * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local @@ -45,6 +48,25 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no ) or nodeTo.(LoadInstruction).getSourceAddress() = nodeFrom + or + modeledInstructionTaintStep(nodeFrom, nodeTo) + or + // Flow through partial reads of arrays and unions + nodeTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = nodeFrom and + not nodeFrom.isResultConflated() and + ( + nodeFrom.getResultType() instanceof ArrayType or + nodeFrom.getResultType() instanceof Union + ) + or + // Flow from an element to an array or union that contains it. + nodeTo.(ChiInstruction).getPartial() = nodeFrom and + not nodeTo.isResultConflated() and + exists(Type t | nodeTo.getResultLanguageType().hasType(t, false) | + t instanceof Union + or + t instanceof ArrayType + ) } /** @@ -82,3 +104,34 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) { * but not in local taint. */ predicate defaultTaintBarrier(DataFlow::Node node) { none() } + +/** + * Holds if taint can flow from `instrIn` to `instrOut` through a call to a + * modeled function. + */ +predicate modeledInstructionTaintStep(Instruction instrIn, Instruction instrOut) { + exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut | + instrIn = callInput(call, modelIn) and + instrOut = callOutput(call, modelOut) and + call.getStaticCallTarget() = func and + func.hasTaintFlow(modelIn, modelOut) + ) + or + // Taint flow from one argument to another and data flow from an argument to a + // return value. This happens in functions like `strcat` and `memcpy`. We + // could model this flow in two separate steps, but that would add reverse + // flow from the write side-effect to the call instruction, which may not be + // desirable. + exists( + CallInstruction call, Function func, FunctionInput modelIn, OutParameterDeref modelMidOut, + int indexMid, InParameter modelMidIn, OutReturnValue modelOut + | + instrIn = callInput(call, modelIn) and + instrOut = callOutput(call, modelOut) and + call.getStaticCallTarget() = func and + func.(TaintFunction).hasTaintFlow(modelIn, modelMidOut) and + func.(DataFlowFunction).hasDataFlow(modelMidIn, modelOut) and + modelMidOut.isParameterDeref(indexMid) and + modelMidIn.isParameter(indexMid) + ) +} 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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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..54059fb5b82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -17,6 +17,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,8 +29,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 +37,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 +45,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 +53,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 +61,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. @@ -91,4 +82,48 @@ class CaseEdge extends EdgeKind, TCaseEdge { 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/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 833c929ecc5..dec78b413b3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -12,7 +12,9 @@ private newtype TIRType = TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or - TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or + TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { + Language::hasFloatingPointType(byteSize, base, domain) + } or TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) { @@ -104,11 +106,13 @@ private class IRSizedType extends IRType { this = TIRBooleanType(byteSize) or this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) or + this = TIRFloatingPointType(byteSize, _, _) or this = TIRAddressType(byteSize) or 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. } /** @@ -126,22 +130,36 @@ 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 { IRNumericType() { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) + 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) + } + // 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() { @@ -156,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { * 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() { @@ -171,14 +189,43 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { * A floating-point type. */ class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { - final override string toString() { result = "float" + byteSize.toString() } + final private int base; + final private Language::TypeDomain domain; + + IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) } + + final override string toString() { + result = getDomainPrefix() + getBaseString() + byteSize.toString() + } final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalFloatingPointType(byteSize) + result = Language::getCanonicalFloatingPointType(byteSize, base, domain) } pragma[noinline] final override int getByteSize() { result = byteSize } + + /** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */ + final int getBase() { result = base } + + /** + * Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`. + */ + final Language::TypeDomain getDomain() { result = domain } + + private string getBaseString() { + base = 2 and result = "float" + or + base = 10 and result = "decimal" + } + + private string getDomainPrefix() { + domain instanceof Language::RealDomain and result = "" + or + domain instanceof Language::ComplexDomain and result = "c" + or + domain instanceof Language::ImaginaryDomain and result = "i" + } } /** @@ -244,12 +291,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 = @@ -257,11 +316,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 = @@ -269,5 +334,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..6852a965401 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -92,11 +92,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..c0b8adbe56b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -60,8 +60,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -579,22 +577,6 @@ module Opcode { 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 - } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } 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..a0c0ca67530 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,16 @@ +/** + * 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 { string toString() { result = getTempVariableTagId(this) } } 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 49cb4dd6dc4..94ef73b2769 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 @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { 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() ) } @@ -101,23 +105,24 @@ class IRBlock extends IRBlockBase { private predicate startsBasicBlock(Instruction instr) { not instr instanceof PhiInstruction and - ( - count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor - or - exists(Instruction predecessor | - instr = predecessor.getASuccessor() and - strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 - ) // Predecessor has multiple successors - or - exists(Instruction predecessor, EdgeKind kind | - instr = predecessor.getSuccessor(kind) and - not kind instanceof GotoEdge - ) // Incoming edge is not a GotoEdge - or - exists(Instruction predecessor | - instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) - ) // A back edge enters this instruction - ) + not adjacentInBlock(_, instr) +} + +/** Holds if `i2` follows `i1` in a `IRBlock`. */ +private predicate adjacentInBlock(Instruction i1, Instruction i2) { + // - i2 must be the only successor of i1 + i2 = unique(Instruction i | i = i1.getASuccessor()) and + // - i1 must be the only predecessor of i2 + i1 = unique(Instruction i | i.getASuccessor() = i2) and + // - The edge between the two must be a GotoEdge. We just check that one + // exists since we've already checked that it's unique. + exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and + // - The edge must not be a back edge. This means we get the same back edges + // in the basic-block graph as we do in the raw CFG. + not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) + // This predicate could be simplified to remove one of the `unique`s if we + // were willing to rely on the CFG being well-formed and thus never having + // more than one successor to an instruction that has a `GotoEdge` out of it. } private predicate isEntryBlock(TIRBlock block) { @@ -129,12 +134,6 @@ private module Cached { cached newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - /** Holds if `i2` follows `i1` in a `IRBlock`. */ - private predicate adjacentInBlock(Instruction i1, Instruction i2) { - exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and - not startsBasicBlock(i2) - } - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ private Instruction getInstructionFromFirst(Instruction first, int index) = shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) 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..6b2d32af48c 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,12 @@ 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 +23,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 94d0192fe18..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll +++ /dev/null @@ -1,320 +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 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..a01bd2dc79a 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 @@ -217,10 +217,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 } } /** @@ -265,3 +278,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 38216872f2b..409577d3e46 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 @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation 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) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -190,17 +196,18 @@ class Instruction extends Construction::TInstruction { final Language::Location getLocation() { result = getAST().getLocation() } /** - * Gets the `Expr` whose result is computed by this instruction, if any. + * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a + * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** - * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + * 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) } final Language::LanguageType getResultLanguageType() { @@ -211,6 +218,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() } /** @@ -249,7 +257,7 @@ class Instruction extends Construction::TInstruction { * 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 @@ -258,7 +266,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. @@ -319,8 +327,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: * ``` @@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -410,7 +417,7 @@ class VariableInstruction extends 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() } @@ -420,7 +427,7 @@ class FieldInstruction extends 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() } @@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -541,6 +548,11 @@ 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 } } class CopyInstruction extends Instruction { @@ -584,9 +596,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -598,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { @@ -699,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -748,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -906,7 +923,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -1211,7 +1228,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() } @@ -1229,10 +1246,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. */ @@ -1247,12 +1260,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. * @@ -1367,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } 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..f82704094c8 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 @@ -14,16 +14,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,6 +23,57 @@ 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. */ @@ -104,7 +147,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 +222,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,18 +257,15 @@ 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() } @@ -226,8 +276,15 @@ class NonPhiOperand extends Operand { /** * 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,13 +292,25 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +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 + } } class TypedOperand extends NonPhiMemoryOperand { @@ -258,8 +327,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +335,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +343,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +350,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +357,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +364,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +371,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +378,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 +385,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +402,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +409,27 @@ 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() } } 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 +459,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 +468,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/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll index 40076b817a1..76f52f8334a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/constant/ConstantAnalysis.qll @@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) { or exists(PhiInstruction phi | phi = instr and - result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and - result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) + result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) ) } 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..1612e0065b7 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 @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and @@ -247,6 +247,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/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll index dc02760c7c4..72bb239c153 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA 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/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 49cb4dd6dc4..94ef73b2769 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 @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { 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() ) } @@ -101,23 +105,24 @@ class IRBlock extends IRBlockBase { private predicate startsBasicBlock(Instruction instr) { not instr instanceof PhiInstruction and - ( - count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor - or - exists(Instruction predecessor | - instr = predecessor.getASuccessor() and - strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 - ) // Predecessor has multiple successors - or - exists(Instruction predecessor, EdgeKind kind | - instr = predecessor.getSuccessor(kind) and - not kind instanceof GotoEdge - ) // Incoming edge is not a GotoEdge - or - exists(Instruction predecessor | - instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) - ) // A back edge enters this instruction - ) + not adjacentInBlock(_, instr) +} + +/** Holds if `i2` follows `i1` in a `IRBlock`. */ +private predicate adjacentInBlock(Instruction i1, Instruction i2) { + // - i2 must be the only successor of i1 + i2 = unique(Instruction i | i = i1.getASuccessor()) and + // - i1 must be the only predecessor of i2 + i1 = unique(Instruction i | i.getASuccessor() = i2) and + // - The edge between the two must be a GotoEdge. We just check that one + // exists since we've already checked that it's unique. + exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and + // - The edge must not be a back edge. This means we get the same back edges + // in the basic-block graph as we do in the raw CFG. + not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) + // This predicate could be simplified to remove one of the `unique`s if we + // were willing to rely on the CFG being well-formed and thus never having + // more than one successor to an instruction that has a `GotoEdge` out of it. } private predicate isEntryBlock(TIRBlock block) { @@ -129,12 +134,6 @@ private module Cached { cached newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - /** Holds if `i2` follows `i1` in a `IRBlock`. */ - private predicate adjacentInBlock(Instruction i1, Instruction i2) { - exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and - not startsBasicBlock(i2) - } - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ private Instruction getInstructionFromFirst(Instruction first, int index) = shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) 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..6b2d32af48c 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,12 @@ 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 +23,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 94d0192fe18..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ /dev/null @@ -1,320 +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 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..a01bd2dc79a 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 @@ -217,10 +217,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 } } /** @@ -265,3 +278,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 38216872f2b..409577d3e46 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 @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation 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) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -190,17 +196,18 @@ class Instruction extends Construction::TInstruction { final Language::Location getLocation() { result = getAST().getLocation() } /** - * Gets the `Expr` whose result is computed by this instruction, if any. + * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a + * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** - * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + * 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) } final Language::LanguageType getResultLanguageType() { @@ -211,6 +218,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() } /** @@ -249,7 +257,7 @@ class Instruction extends Construction::TInstruction { * 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 @@ -258,7 +266,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. @@ -319,8 +327,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: * ``` @@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -410,7 +417,7 @@ class VariableInstruction extends 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() } @@ -420,7 +427,7 @@ class FieldInstruction extends 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() } @@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -541,6 +548,11 @@ 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 } } class CopyInstruction extends Instruction { @@ -584,9 +596,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -598,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { @@ -699,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -748,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -906,7 +923,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -1211,7 +1228,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() } @@ -1229,10 +1246,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. */ @@ -1247,12 +1260,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. * @@ -1367,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } 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..f82704094c8 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 @@ -14,16 +14,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,6 +23,57 @@ 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. */ @@ -104,7 +147,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 +222,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,18 +257,15 @@ 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() } @@ -226,8 +276,15 @@ class NonPhiOperand extends Operand { /** * 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,13 +292,25 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +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 + } } class TypedOperand extends NonPhiMemoryOperand { @@ -258,8 +327,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +335,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +343,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +350,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +357,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +364,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +371,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +378,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 +385,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +402,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +409,27 @@ 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() } } 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 +459,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 +468,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/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll index 40076b817a1..76f52f8334a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll @@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) { or exists(PhiInstruction phi | phi = instr and - result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and - result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) + result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) ) } 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 2f143bf02ca..8bf5fa9d44b 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 @@ -200,7 +200,11 @@ private predicate usedAsCondition(Expr expr) { or exists(IfStmt ifStmt | ifStmt.getCondition().getFullyConverted() = expr) or - exists(ConditionalExpr condExpr | condExpr.getCondition().getFullyConverted() = expr) + exists(ConditionalExpr condExpr | + // The two-operand form of `ConditionalExpr` treats its condition as a value, since it needs to + // be reused as a value if the condition is true. + condExpr.getCondition().getFullyConverted() = expr and not condExpr.isTwoOperand() + ) or exists(NotExpr notExpr | notExpr.getOperand().getFullyConverted() = expr and @@ -396,6 +400,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 | @@ -408,8 +415,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 @@ -456,7 +466,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) { ( @@ -695,12 +705,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() } /** @@ -732,12 +738,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 b8ede454ba2..75e70d1986f 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() @@ -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 @@ -1100,13 +1107,36 @@ private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) { } private Opcode binaryArithmeticOpcode(BinaryArithmeticOperation expr) { - expr instanceof AddExpr and result instanceof Opcode::Add + ( + expr instanceof AddExpr + or + expr instanceof ImaginaryRealAddExpr + or + expr instanceof RealImaginaryAddExpr + ) and + result instanceof Opcode::Add or - expr instanceof SubExpr and result instanceof Opcode::Sub + ( + expr instanceof SubExpr + or + expr instanceof ImaginaryRealSubExpr + or + expr instanceof RealImaginarySubExpr + ) and + result instanceof Opcode::Sub or - expr instanceof MulExpr and result instanceof Opcode::Mul + ( + expr instanceof MulExpr + or + expr instanceof ImaginaryMulExpr + ) and + result instanceof Opcode::Mul or - expr instanceof DivExpr and result instanceof Opcode::Div + ( + expr instanceof DivExpr or + expr instanceof ImaginaryDivExpr + ) and + result instanceof Opcode::Div or expr instanceof RemExpr and result instanceof Opcode::Rem or @@ -1149,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 ( @@ -1283,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 @@ -1459,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 @@ -1603,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()) @@ -1668,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()) } } @@ -1719,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() @@ -1735,20 +1766,20 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St private TranslatedExpr getDestructorCall() { result = getTranslatedExpr(expr.getExpr()) } } -class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionContext { +/** + * The IR translation of the `?:` operator. This class has the portions of the implementation that + * are shared between the standard three-operand form (`a ? b : c`) and the GCC-extension + * two-operand form (`a ?: c`). + */ +abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { override ConditionalExpr expr; - final override TranslatedElement getChild(int id) { - id = 0 and result = getCondition() - or - id = 1 and result = getThen() - or - id = 2 and result = getElse() - } - - override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + // Note that the ternary flavor needs no explicit `ConditionalBranch` instruction here, because + // the condition is a `TranslatedCondition`, which will simply connect the successor edges of + // the condition directly to the appropriate then/else block via + // `getChild[True|False]Successor()`. + // The binary flavor will override this predicate to add the `ConditionalBranch`. not resultIsVoid() and ( ( @@ -1809,7 +1840,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { not resultIsVoid() and ( not thenIsVoid() and @@ -1836,20 +1867,17 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ( operandTag instanceof AddressOperandTag and result = getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) ) } - override predicate hasTempVariable(TempVariableTag tag, CppType type) { + final override predicate hasTempVariable(TempVariableTag tag, CppType type) { not resultIsVoid() and tag = ConditionValueTempVar() and type = getResultType() } - override IRVariable getInstructionVariable(InstructionTag tag) { + final override IRVariable getInstructionVariable(InstructionTag tag) { not resultIsVoid() and ( tag = ConditionValueTrueTempAddressTag() or @@ -1859,25 +1887,75 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont result = getTempVariable(ConditionValueTempVar()) } - override Instruction getResult() { + final override Instruction getResult() { not resultIsVoid() and result = getInstruction(ConditionValueResultLoadTag()) } override Instruction getChildSuccessor(TranslatedElement child) { + child = getElse() and + if elseIsVoid() + then result = getParent().getChildSuccessor(this) + else result = getInstruction(ConditionValueFalseTempAddressTag()) + } + + /** + * Gets the `TranslatedExpr` for the "then" result. Note that nothing in the base implementation + * of this class assumes that `getThen()` is disjoint from `getCondition()`. + */ + abstract TranslatedExpr getThen(); + + /** + * Gets the `TranslatedExpr` for the "else" result. + */ + final TranslatedExpr getElse() { result = getTranslatedExpr(expr.getElse().getFullyConverted()) } + + final predicate thenIsVoid() { + getThen().getResultType().getIRType() instanceof IRVoidType + or + // A `ThrowExpr.getType()` incorrectly returns the type of exception being + // thrown, rather than `void`. Handle that case here. + expr.getThen() instanceof ThrowExpr + } + + private predicate elseIsVoid() { + getElse().getResultType().getIRType() instanceof IRVoidType + or + // A `ThrowExpr.getType()` incorrectly returns the type of exception being + // thrown, rather than `void`. Handle that case here. + expr.getElse() instanceof ThrowExpr + } + + private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType } +} + +/** + * The IR translation of the ternary conditional operator (`a ? b : c`). + * For this version, we expand the condition as a `TranslatedCondition`, rather than a + * `TranslatedExpr`, to simplify the control flow in the presence of short-ciruit logical operators. + */ +class TranslatedTernaryConditionalExpr extends TranslatedConditionalExpr, ConditionContext { + TranslatedTernaryConditionalExpr() { not expr.isTwoOperand() } + + final override TranslatedElement getChild(int id) { + id = 0 and result = getCondition() + or + id = 1 and result = getThen() + or + id = 2 and result = getElse() + } + + override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + + override Instruction getChildSuccessor(TranslatedElement child) { + result = TranslatedConditionalExpr.super.getChildSuccessor(child) + or ( child = getThen() and if thenIsVoid() then result = getParent().getChildSuccessor(this) else result = getInstruction(ConditionValueTrueTempAddressTag()) ) - or - ( - child = getElse() and - if elseIsVoid() - then result = getParent().getChildSuccessor(this) - else result = getInstruction(ConditionValueFalseTempAddressTag()) - ) } override Instruction getChildTrueSuccessor(TranslatedCondition child) { @@ -1894,31 +1972,81 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont result = getTranslatedCondition(expr.getCondition().getFullyConverted()) } - private TranslatedExpr getThen() { + final override TranslatedExpr getThen() { result = getTranslatedExpr(expr.getThen().getFullyConverted()) } +} - private TranslatedExpr getElse() { - result = getTranslatedExpr(expr.getElse().getFullyConverted()) - } +/** + * The IR translation of a two-operand conditional operator (`a ?: b`). This is a GCC language + * extension. + * This version of the conditional expression returns its first operand (the condition) if that + * condition is non-zero. Since we'll be reusing the value of the condition, we'll compute that + * value directly before branching, even if that value was a short-circuit logical expression. + */ +class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { + TranslatedBinaryConditionalExpr() { expr.isTwoOperand() } - private predicate thenIsVoid() { - getThen().getResultType().getIRType() instanceof IRVoidType + final override TranslatedElement getChild(int id) { + // We only truly have two children, because our "condition" and "then" are the same as far as + // the extractor is concerned. + id = 0 and result = getCondition() or - // A `ThrowExpr.getType()` incorrectly returns the type of exception being - // thrown, rather than `void`. Handle that case here. - expr.getThen() instanceof ThrowExpr + id = 1 and result = getElse() } - private predicate elseIsVoid() { - getElse().getResultType().getIRType() instanceof IRVoidType + override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + super.hasInstruction(opcode, tag, resultType) or - // A `ThrowExpr.getType()` incorrectly returns the type of exception being - // thrown, rather than `void`. Handle that case here. - expr.getElse() instanceof ThrowExpr + // For the binary variant, we create our own conditional branch. + tag = ValueConditionConditionalBranchTag() and + opcode instanceof Opcode::ConditionalBranch and + resultType = getVoidType() } - private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType } + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + result = super.getInstructionSuccessor(tag, kind) + or + tag = ValueConditionConditionalBranchTag() and + ( + kind instanceof TrueEdge and + result = getInstruction(ConditionValueTrueTempAddressTag()) + or + kind instanceof FalseEdge and + result = getElse().getFirstInstruction() + ) + } + + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = super.getInstructionRegisterOperand(tag, operandTag) + or + tag = ValueConditionConditionalBranchTag() and + operandTag instanceof ConditionOperandTag and + result = getCondition().getResult() + } + + override Instruction getChildSuccessor(TranslatedElement child) { + result = super.getChildSuccessor(child) + or + child = getCondition() and result = getInstruction(ValueConditionConditionalBranchTag()) + } + + private TranslatedExpr getCondition() { + result = getTranslatedExpr(expr.getCondition().getFullyConverted()) + } + + final override TranslatedExpr getThen() { + // The extractor returns the exact same expression for `ConditionalExpr::getCondition()` and + // `ConditionalExpr::getThen()`, even though the condition may have been converted to `bool`, + // and the "then" may have been converted to the result type. We'll strip the top-level implicit + // conversions from this, to skip any conversion to `bool`. We don't have enough information to + // know how to convert the result to the destination type, especially in the class pointer case, + // so we'll still sometimes wind up with one operand as the wrong type. This is better than + // always converting the "then" operand to `bool`, which is almost always the wrong type. + result = getTranslatedExpr(expr.getThen().getExplicitlyConverted()) + } } /** @@ -1970,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()) @@ -2068,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 @@ -2188,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()) @@ -2259,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 @@ -2319,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() @@ -2380,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 @@ -2437,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() @@ -2500,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() } @@ -2534,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() } @@ -2638,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()) @@ -2647,9 +2768,6 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -2709,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() @@ -2733,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 2c54fdf539a..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 @@ -49,6 +49,11 @@ CppType getEllipsisVariablePRValueType() { CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) } +/** + * Holds if the function returns a value, as opposed to returning `void`. + */ +predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instanceof VoidType } + /** * Represents the IR translation of a function. This is the root elements for * all other elements associated with this function. @@ -68,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() { @@ -92,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 @@ -109,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 @@ -177,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() @@ -189,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 @@ -216,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() @@ -234,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 @@ -287,6 +254,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = EllipsisTempVar() and func.isVarargs() and type = getEllipsisVariablePRValueType() + or + tag = ThisTempVar() and + type = getTypeForGLValue(getThisType()) } /** @@ -310,22 +280,22 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final IREllipsisVariable getEllipsisVariable() { result.getEnclosingFunction() = func } /** - * Holds if the function has a non-`void` return type. + * Gets the variable that represents the `this` pointer for this function, if any. */ - final predicate hasReturnValue() { not func.getUnspecifiedType() instanceof VoidType } + final IRThisVariable getThisVariable() { result = getIRTempVariable(func, ThisTempVar()) } /** - * Gets the single `UnmodeledDefinition` instruction for this function. + * Holds if the function has a non-`void` return type. */ - final Instruction getUnmodeledDefinitionInstruction() { - result = getInstruction(UnmodeledDefinitionTag()) - } + final predicate hasReturnValue() { hasReturnValue(func) } /** * 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`). @@ -366,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`. */ @@ -380,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() } @@ -428,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) { @@ -440,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 @@ -452,9 +428,6 @@ abstract class TranslatedParameter extends TranslatedElement { ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getInstruction(InitializerStoreTag()) ) or tag = InitializerIndirectStoreTag() and @@ -468,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. @@ -501,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) } @@ -527,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() } @@ -665,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) } @@ -698,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 88a7d4c99ea..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 @@ -131,8 +131,11 @@ abstract class TranslatedReturnStmt extends TranslatedStmt { } } +/** + * The IR translation of a `return` statement that returns a value. + */ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariableInitialization { - TranslatedReturnValueStmt() { stmt.hasExpr() } + TranslatedReturnValueStmt() { stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction()) } final override Instruction getInitializationSuccessor() { result = getEnclosingFunction().getReturnSuccessorInstruction() @@ -147,8 +150,49 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariable final override IRVariable getIRVariable() { result = getEnclosingFunction().getReturnVariable() } } +/** + * The IR translation of a `return` statement that returns an expression of `void` type. + */ +class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt { + TranslatedReturnVoidExpressionStmt() { + stmt.hasExpr() and not hasReturnValue(stmt.getEnclosingFunction()) + } + + override TranslatedElement getChild(int id) { + id = 0 and + result = getExpr() + } + + override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + tag = OnlyInstructionTag() and + opcode instanceof Opcode::NoOp and + resultType = getVoidType() + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + tag = OnlyInstructionTag() and + result = getEnclosingFunction().getReturnSuccessorInstruction() and + kind instanceof GotoEdge + } + + override Instruction getChildSuccessor(TranslatedElement child) { + child = getExpr() and + result = getInstruction(OnlyInstructionTag()) + } + + private TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) } +} + +/** + * The IR translation of a `return` statement that does not return a value. This includes implicit + * return statements at the end of `void`-returning functions. + */ class TranslatedReturnVoidStmt extends TranslatedReturnStmt { - TranslatedReturnVoidStmt() { not stmt.hasExpr() } + TranslatedReturnVoidStmt() { + not stmt.hasExpr() and not hasReturnValue(stmt.getEnclosingFunction()) + } override TranslatedElement getChild(int id) { none() } @@ -169,6 +213,33 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt { override Instruction getChildSuccessor(TranslatedElement child) { none() } } +/** + * The IR translation of an implicit `return` statement generated by the extractor to handle control + * flow that reaches the end of a non-`void`-returning function body. Since such control flow + * produces undefined behavior, we simply generate an `Unreached` instruction to prevent that flow + * from continuing on to pollute other analysis. The assumption is that the developer is certain + * that the implicit `return` is unreachable, even if the compiler cannot prove it. + */ +class TranslatedUnreachableReturnStmt extends TranslatedReturnStmt { + TranslatedUnreachableReturnStmt() { + not stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction()) + } + + override TranslatedElement getChild(int id) { none() } + + override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + tag = OnlyInstructionTag() and + opcode instanceof Opcode::Unreached and + resultType = getVoidType() + } + + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } + + override Instruction getChildSuccessor(TranslatedElement child) { none() } +} + /** * The IR translation of a C++ `try` statement. */ @@ -642,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() @@ -688,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 @@ -700,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/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 49cb4dd6dc4..94ef73b2769 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 @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { 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() ) } @@ -101,23 +105,24 @@ class IRBlock extends IRBlockBase { private predicate startsBasicBlock(Instruction instr) { not instr instanceof PhiInstruction and - ( - count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor - or - exists(Instruction predecessor | - instr = predecessor.getASuccessor() and - strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 - ) // Predecessor has multiple successors - or - exists(Instruction predecessor, EdgeKind kind | - instr = predecessor.getSuccessor(kind) and - not kind instanceof GotoEdge - ) // Incoming edge is not a GotoEdge - or - exists(Instruction predecessor | - instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) - ) // A back edge enters this instruction - ) + not adjacentInBlock(_, instr) +} + +/** Holds if `i2` follows `i1` in a `IRBlock`. */ +private predicate adjacentInBlock(Instruction i1, Instruction i2) { + // - i2 must be the only successor of i1 + i2 = unique(Instruction i | i = i1.getASuccessor()) and + // - i1 must be the only predecessor of i2 + i1 = unique(Instruction i | i.getASuccessor() = i2) and + // - The edge between the two must be a GotoEdge. We just check that one + // exists since we've already checked that it's unique. + exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and + // - The edge must not be a back edge. This means we get the same back edges + // in the basic-block graph as we do in the raw CFG. + not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) + // This predicate could be simplified to remove one of the `unique`s if we + // were willing to rely on the CFG being well-formed and thus never having + // more than one successor to an instruction that has a `GotoEdge` out of it. } private predicate isEntryBlock(TIRBlock block) { @@ -129,12 +134,6 @@ private module Cached { cached newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - /** Holds if `i2` follows `i1` in a `IRBlock`. */ - private predicate adjacentInBlock(Instruction i1, Instruction i2) { - exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and - not startsBasicBlock(i2) - } - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ private Instruction getInstructionFromFirst(Instruction first, int index) = shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) 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..6b2d32af48c 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,12 @@ 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 +23,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 94d0192fe18..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll +++ /dev/null @@ -1,320 +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 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..a01bd2dc79a 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 @@ -217,10 +217,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 } } /** @@ -265,3 +278,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 38216872f2b..409577d3e46 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 @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation 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) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -190,17 +196,18 @@ class Instruction extends Construction::TInstruction { final Language::Location getLocation() { result = getAST().getLocation() } /** - * Gets the `Expr` whose result is computed by this instruction, if any. + * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a + * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** - * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + * 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) } final Language::LanguageType getResultLanguageType() { @@ -211,6 +218,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() } /** @@ -249,7 +257,7 @@ class Instruction extends Construction::TInstruction { * 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 @@ -258,7 +266,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. @@ -319,8 +327,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: * ``` @@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -410,7 +417,7 @@ class VariableInstruction extends 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() } @@ -420,7 +427,7 @@ class FieldInstruction extends 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() } @@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -541,6 +548,11 @@ 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 } } class CopyInstruction extends Instruction { @@ -584,9 +596,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -598,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { @@ -699,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -748,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -906,7 +923,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -1211,7 +1228,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() } @@ -1229,10 +1246,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. */ @@ -1247,12 +1260,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. * @@ -1367,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } 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..f82704094c8 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 @@ -14,16 +14,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,6 +23,57 @@ 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. */ @@ -104,7 +147,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 +222,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,18 +257,15 @@ 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() } @@ -226,8 +276,15 @@ class NonPhiOperand extends Operand { /** * 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,13 +292,25 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +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 + } } class TypedOperand extends NonPhiMemoryOperand { @@ -258,8 +327,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +335,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +343,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +350,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +357,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +364,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +371,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +378,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 +385,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +402,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +409,27 @@ 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() } } 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 +459,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 +468,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/constant/ConstantAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index 40076b817a1..76f52f8334a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -14,8 +14,7 @@ int getConstantValue(Instruction instr) { or exists(PhiInstruction phi | phi = instr and - result = max(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) and - result = min(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) + result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef())) ) } 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..1612e0065b7 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 @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and @@ -247,6 +247,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/PrintSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll index dc02760c7c4..72bb239c153 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA 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 9e8044ede4f..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()) } @@ -86,9 +86,15 @@ predicate hasUnsignedIntegerType(int byteSize) { } /** - * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist. + * Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist. */ -predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() } +predicate hasFloatingPointType(int byteSize, int base, TypeDomain domain) { + exists(FloatingPointType type | + byteSize = type.getSize() and + base = type.getBase() and + domain = type.getDomain() + ) +} private predicate isPointerIshType(Type type) { type instanceof PointerType @@ -137,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) } /** @@ -159,8 +165,13 @@ private IRType getIRTypeForPRValue(Type type) { isUnsignedIntegerType(unspecifiedType) and result.(IRUnsignedIntegerType).getByteSize() = type.getSize() or - unspecifiedType instanceof FloatingPointType and - result.(IRFloatingPointType).getByteSize() = type.getSize() + exists(FloatingPointType floatType, IRFloatingPointType irFloatType | + floatType = unspecifiedType and + irFloatType = result and + irFloatType.getByteSize() = floatType.getSize() and + irFloatType.getBase() = floatType.getBase() and + irFloatType.getDomain() = floatType.getDomain() + ) or isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type) or @@ -180,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() /** @@ -192,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 */ @@ -213,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 @@ -346,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`. @@ -438,15 +454,37 @@ CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) { } /** - * Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified - * `byteSize`. + * Gets the sort priority of a `RealNumberType` base on its precision. */ -CppPRValueType getCanonicalFloatingPointType(int byteSize) { +private int getPrecisionPriority(RealNumberType type) { + // Prefer `double`, `float`, `long double` in that order. + if type instanceof DoubleType + then result = 4 + else + if type instanceof FloatType + then result = 3 + else + if type instanceof LongDoubleType + then result = 2 + else + // If we get this far, prefer non-extended-precision types. + if not type.isExtendedPrecision() + then result = 1 + else result = 0 +} + +/** + * Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified + * size, base, and type domain. + */ +CppPRValueType getCanonicalFloatingPointType(int byteSize, int base, TypeDomain domain) { result = TPRValueType(max(FloatingPointType type | - type.getSize() = byteSize + type.getSize() = byteSize and + type.getBase() = base and + type.getDomain() = domain | - type order by type.toString() desc + type order by getPrecisionPriority(type.getRealType()), type.toString() desc )) } @@ -506,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/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll index 6e88e711711..f047d6c4753 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll @@ -9,6 +9,14 @@ class LanguageType = CppType; class OpaqueTypeTag = Cpp::Type; +class TypeDomain = Cpp::TypeDomain; + +class RealDomain = Cpp::RealDomain; + +class ComplexDomain = Cpp::ComplexDomain; + +class ImaginaryDomain = Cpp::ImaginaryDomain; + class Function = Cpp::Function; class Location = Cpp::Location; diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll index 53c15663796..6b2b4c918af 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRUtilities.qll @@ -23,17 +23,20 @@ Type getVariableType(Variable v) { then result = getDecayedType(declaredType) or - not exists(getDecayedType(declaredType)) and result = declaredType + not exists(getDecayedType(declaredType)) and result = v.getType() else if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize() then - result = v.getInitializer().getExpr().getUnspecifiedType() + result = v.getInitializer().getExpr().getType() or - not exists(v.getInitializer()) and result = declaredType - else result = declaredType + not exists(v.getInitializer()) and result = v.getType() + else result = v.getType() ) } +/** + * Holds if the database contains a `case` label with the specified minimum and maximum value. + */ predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) { minValue = switchCase.getExpr().getFullyConverted().getValue() and if exists(switchCase.getEndExpr()) 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..82ae1fdc4f0 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -14,3 +14,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 f6f7ab279a6..782800d0fa2 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -89,6 +89,18 @@ class MallocAllocationFunction extends AllocationFunction { or // kmem_zalloc(size, flags) name = "kmem_zalloc" and sizeArg = 0 + or + // CRYPTO_malloc(size_t num, const char *file, int line) + name = "CRYPTO_malloc" and sizeArg = 0 + or + // CRYPTO_zalloc(size_t num, const char *file, int line) + name = "CRYPTO_zalloc" and sizeArg = 0 + or + // CRYPTO_secure_malloc(size_t num, const char *file, int line) + name = "CRYPTO_secure_malloc" and sizeArg = 0 + or + // CRYPTO_secure_zalloc(size_t num, const char *file, int line) + name = "CRYPTO_secure_zalloc" and sizeArg = 0 ) ) } @@ -169,6 +181,9 @@ class ReallocAllocationFunction extends AllocationFunction { or // CoTaskMemRealloc(ptr, size) name = "CoTaskMemRealloc" and sizeArg = 1 and reallocArg = 0 + or + // CRYPTO_realloc(void *addr, size_t num, const char *file, int line); + name = "CRYPTO_realloc" and sizeArg = 1 and reallocArg = 0 ) ) } @@ -255,6 +270,35 @@ class OperatorNewAllocationFunction extends AllocationFunction { } } +/** + * Holds if `sizeExpr` is an expression consisting of a subexpression + * `lengthExpr` multiplied by a constant `sizeof` that is the result of a + * `sizeof()` expression. Alternatively if there isn't a suitable `sizeof()` + * expression, `lengthExpr = sizeExpr` and `sizeof = 1`. For example: + * ``` + * malloc(a * 2 * sizeof(char32_t)); + * ``` + * In this case if the `sizeExpr` is the argument to `malloc`, the `lengthExpr` + * is `a * 2` and `sizeof` is `4`. + */ +private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof) { + exists(SizeofOperator sizeofOp | + sizeofOp = sizeExpr.(MulExpr).getAnOperand() and + lengthExpr = sizeExpr.(MulExpr).getAnOperand() and + not lengthExpr instanceof SizeofOperator and + sizeof = sizeofOp.getValue().toInt() + ) + or + not exists(SizeofOperator sizeofOp, Expr lengthOp | + sizeofOp = sizeExpr.(MulExpr).getAnOperand() and + lengthOp = sizeExpr.(MulExpr).getAnOperand() and + not lengthOp instanceof SizeofOperator and + exists(sizeofOp.getValue().toInt()) + ) and + lengthExpr = sizeExpr and + sizeof = 1 +} + /** * An allocation expression that is a function call, such as call to `malloc`. */ @@ -272,7 +316,17 @@ class CallAllocationExpr extends AllocationExpr, FunctionCall { not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this) } - override Expr getSizeExpr() { result = getArgument(target.getSizeArg()) } + override Expr getSizeExpr() { + exists(Expr sizeExpr | sizeExpr = getArgument(target.getSizeArg()) | + if exists(target.getSizeMult()) + then result = sizeExpr + else + exists(Expr lengthExpr | + deconstructSizeExpr(sizeExpr, lengthExpr, _) and + result = lengthExpr + ) + ) + } override int getSizeMult() { // malloc with multiplier argument that is a constant @@ -280,13 +334,19 @@ class CallAllocationExpr extends AllocationExpr, FunctionCall { or // malloc with no multiplier argument not exists(target.getSizeMult()) and - result = 1 + deconstructSizeExpr(getArgument(target.getSizeArg()), _, result) } override int getSizeBytes() { result = getSizeExpr().getValue().toInt() * getSizeMult() } override Expr getReallocPtr() { result = getArgument(target.getReallocPtrArg()) } + override Type getAllocatedElementType() { + result = + this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and + not result instanceof VoidType + } + override predicate requiresDealloc() { target.requiresDealloc() } } @@ -298,6 +358,8 @@ class NewAllocationExpr extends AllocationExpr, NewExpr { override int getSizeBytes() { result = getAllocatedType().getSize() } + override Type getAllocatedElementType() { result = getAllocatedType() } + override predicate requiresDealloc() { not exists(getPlacementPointer()) } } @@ -318,6 +380,8 @@ class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr { result = getAllocatedElementType().getSize() } + override Type getAllocatedElementType() { result = NewArrayExpr.super.getAllocatedElementType() } + override int getSizeBytes() { result = getAllocatedType().getSize() } override predicate requiresDealloc() { not exists(getPlacementPointer()) } 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 980645df031..2ef355bf398 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -19,6 +19,10 @@ class StandardDeallocationFunction extends DeallocationFunction { name = "free" and freedArg = 0 or name = "realloc" and freedArg = 0 + or + name = "CRYPTO_free" and freedArg = 0 + or + name = "CRYPTO_secure_free" and freedArg = 0 ) or hasGlobalOrStdName(name) and diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll index 8fdf17ead02..4813e5c0066 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll @@ -1,6 +1,7 @@ import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource -class Fread extends AliasFunction { +class Fread extends AliasFunction, RemoteFlowFunction { Fread() { this.hasGlobalName("fread") } override predicate parameterNeverEscapes(int n) { @@ -11,4 +12,9 @@ class Fread extends AliasFunction { override predicate parameterEscapesOnlyViaReturn(int n) { none() } override predicate parameterIsAlwaysReturned(int n) { none() } + + 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/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 aa4091fd7f2..702f56931e7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -3,12 +3,13 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.SideEffect +import semmle.code.cpp.models.interfaces.FlowSource /** * The standard functions `gets` and `fgets`. */ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction, - SideEffectFunction { + SideEffectFunction, RemoteFlowFunction { GetsFunction() { exists(string name | hasGlobalOrStdName(name) | name = "gets" or // gets(str) @@ -42,4 +43,22 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias buffer = true and mustWrite = true } + + override predicate hasRemoteFlowSource(FunctionOutput output, string description) { + 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/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 403e8fae1de..b5047c25e85 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -19,7 +19,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 +47,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 } } @@ -70,7 +70,7 @@ class Sprintf extends FormattingFunction { not exists(getDefinition().getFile().getRelativePath()) } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -136,7 +136,7 @@ class Snprintf extends FormattingFunction { else result = getFirstFormatArgumentIndex() - 1 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -201,7 +201,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 80fe85e9f13..9c6ebd1a877 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -4,6 +4,7 @@ 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) { 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 17aefd8d3c8..81a40cd349a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll @@ -72,6 +72,11 @@ abstract class AllocationExpr extends Expr { */ Expr getReallocPtr() { none() } + /** + * Gets the type of the elements that are allocated, if it can be determined. + */ + Type getAllocatedElementType() { none() } + /** * Whether or not this allocation requires a corresponding deallocation of * some sort (most do, but `alloca` for example does not). If it is unclear, diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll new file mode 100644 index 00000000000..2c9effaff7c --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -0,0 +1,21 @@ +/** + * Provides a class for modeling functions that return data from potentially untrusted sources. To use + * this QL library, create a QL class extending `DataFlowFunction` with a + * characteristic predicate that selects the function or set of functions you + * are modeling. Within that class, override the predicates provided by + * `RemoteFlowFunction` to match the flow within that function. + */ + +import cpp +import FunctionInputsAndOutputs +import semmle.code.cpp.models.Models + +/** + * A library function which returns data read from a network connection. + */ +abstract class RemoteFlowFunction extends Function { + /** + * Holds if remote data described by `description` flows from `output` of a call to this function. + */ + abstract predicate hasRemoteFlowSource(FunctionOutput output, string description); +} 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..78153ca0ec6 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. 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..c619f2efaa5 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -15,6 +15,9 @@ 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 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/padding/Padding.qll b/cpp/ql/src/semmle/code/cpp/padding/Padding.qll index a94c6e501a4..7446569451d 100644 --- a/cpp/ql/src/semmle/code/cpp/padding/Padding.qll +++ b/cpp/ql/src/semmle/code/cpp/padding/Padding.qll @@ -74,6 +74,8 @@ abstract class Architecture extends string { or t instanceof WideCharType and result = wideCharSize() or + t instanceof Char8Type and result = 8 + or t instanceof Char16Type and result = 16 or t instanceof Char32Type and result = 32 @@ -155,6 +157,8 @@ abstract class Architecture extends string { or t instanceof WideCharType and result = wideCharSize() or + t instanceof Char8Type and result = 8 + or t instanceof Char16Type and result = 16 or t instanceof Char32Type and result = 32 diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll index fe0e211087c..9e56794233f 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll @@ -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/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll index af42bb755e3..a79df3c37d7 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll @@ -241,38 +241,6 @@ class CondReason extends Reason, TCondReason { override string toString() { result = getCond().toString() } } -/** - * Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of - * range analysis. - */ -pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and - ( - fromtyp.isUnsigned() - or - totyp.isSigned() - ) - or - fromtyp.getSize() <= totyp.getSize() and - ( - fromtyp.isSigned() and - totyp.isSigned() - or - fromtyp.isUnsigned() and - totyp.isUnsigned() - ) -} - -private class SafeCastInstruction extends ConvertInstruction { - SafeCastInstruction() { - safeCast(getUnary().getResultType(), getResultType()) - or - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType - } -} - /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll index 8935420da8a..ee790404559 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll @@ -80,3 +80,55 @@ predicate backEdge(PhiInstruction phi, PhiInputOperand op) { phi.getAnOperand() = op and phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_) } + +/** + * Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of + * range analysis. + */ +pragma[inline] +private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { + fromtyp.getSize() < totyp.getSize() and + ( + fromtyp.isUnsigned() + or + totyp.isSigned() + ) + or + fromtyp.getSize() <= totyp.getSize() and + ( + fromtyp.isSigned() and + totyp.isSigned() + or + fromtyp.isUnsigned() and + totyp.isUnsigned() + ) +} + +/** + * A `ConvertInstruction` which casts from one pointer type to another. + */ +class PtrToPtrCastInstruction extends ConvertInstruction { + PtrToPtrCastInstruction() { + getResultType() instanceof PointerType and + getUnary().getResultType() instanceof PointerType + } +} + +/** + * A `ConvertInstruction` which casts from one integer type to another in a way + * that cannot overflow or underflow. + */ +class SafeIntCastInstruction extends ConvertInstruction { + SafeIntCastInstruction() { safeCast(getUnary().getResultType(), getResultType()) } +} + +/** + * A `ConvertInstruction` which does not invalidate bounds determined by + * range analysis. + */ +class SafeCastInstruction extends ConvertInstruction { + SafeCastInstruction() { + this instanceof PtrToPtrCastInstruction or + this instanceof SafeIntCastInstruction + } +} diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index ca641f826ef..37e2ac46386 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/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 diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 22e5f5ac83e..867d96b804c 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -118,36 +118,95 @@ private string getValue(Expr e) { ) } +/** + * A bitwise `&` expression in which both operands are unsigned, or are effectively + * unsigned due to being a non-negative constant. + */ +private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { + UnsignedBitwiseAndExpr() { + ( + getLeftOperand().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() or + getLeftOperand().getFullyConverted().getValue().toInt() >= 0 + ) and + ( + getRightOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getRightOperand().getFullyConverted().getValue().toInt() >= 0 + ) + } +} + +/** + * 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 // `exprMinVal` to check this. exists(exprMinVal(e)) and ( - exists(getValue(e).toFloat()) or - e instanceof UnaryPlusExpr or - e instanceof UnaryMinusExpr or - e instanceof MinExpr or - e instanceof MaxExpr or - e instanceof ConditionalExpr or - e instanceof AddExpr or - e instanceof SubExpr or - e instanceof AssignExpr or - e instanceof AssignAddExpr or - e instanceof AssignSubExpr or - e instanceof CrementOperation or - e instanceof RemExpr or - e instanceof CommaExpr or - e instanceof StmtExpr or + exists(getValue(e).toFloat()) + or + e instanceof UnaryPlusExpr + or + e instanceof UnaryMinusExpr + or + e instanceof MinExpr + or + e instanceof MaxExpr + or + e instanceof ConditionalExpr + or + e instanceof AddExpr + or + e instanceof SubExpr + or + e instanceof AssignExpr + or + e instanceof AssignAddExpr + or + e instanceof AssignSubExpr + or + e instanceof CrementOperation + or + e instanceof RemExpr + or + e instanceof CommaExpr + or + e instanceof StmtExpr + or // A conversion is analyzable, provided that its child has an arithmetic // type. (Sometimes the child is a reference type, and so does not get // any bounds.) Rather than checking whether the type of the child is // arithmetic, we reuse the logic that is already encoded in // `exprMinVal`. - exists(exprMinVal(e.(Conversion).getExpr())) or + exists(exprMinVal(e.(Conversion).getExpr())) + or // Also allow variable accesses, provided that they have SSA // information. exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v)) + or + e instanceof UnsignedBitwiseAndExpr + or + // `>>` by a constant + exists(e.(RShiftExpr).getRightOperand().getValue()) ) } @@ -245,6 +304,19 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria or exists(Conversion convExpr | e = convExpr | exprDependsOnDef(convExpr.getExpr(), srcDef, srcVar)) or + // unsigned `&` + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = e and + exprDependsOnDef(andExpr.getAnOperand(), srcDef, srcVar) + ) + or + // `>>` by a constant + exists(RShiftExpr rs | + rs = e and + exists(rs.getRightOperand().getValue()) and + exprDependsOnDef(rs.getLeftOperand(), srcDef, srcVar) + ) + or e = srcDef.getAUse(srcVar) } @@ -641,6 +713,20 @@ private float getLowerBoundsImpl(Expr expr) { exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefLowerBounds(def, v) ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = expr and + result = 0.0 + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and + right = rsExpr.getRightOperand().getValue().toInt() and + result = safeFloor(left / 2.pow(right)) + ) } /** Only to be called by `getTruncatedUpperBounds`. */ @@ -794,6 +880,22 @@ private float getUpperBoundsImpl(Expr expr) { exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | result = getDefUpperBounds(def, v) ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + andExpr = expr and + left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and + right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and + result = left.minimum(right) + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and + right = rsExpr.getRightOperand().getValue().toInt() and + result = safeFloor(left / 2.pow(right)) + ) } /** 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/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll new file mode 100644 index 00000000000..eff40572c02 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -0,0 +1,44 @@ +/** + * Provides classes representing various flow sources for taint tracking. + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.IR +import semmle.code.cpp.models.interfaces.FlowSource + +/** A data flow source of remote user input. */ +abstract class RemoteFlowSource extends DataFlow::Node { + /** Gets a string that describes the type of this remote flow source. */ + abstract string getSourceType(); +} + +private class TaintedReturnSource extends RemoteFlowSource { + string sourceType; + + TaintedReturnSource() { + exists(RemoteFlowFunction func, CallInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getStaticCallTarget() = func and + func.hasRemoteFlowSource(output, sourceType) and + output.isReturnValue() + ) + } + + override string getSourceType() { result = sourceType } +} + +private class TaintedParameterSource extends RemoteFlowSource { + string sourceType; + + TaintedParameterSource() { + exists(RemoteFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + asInstruction() = instr and + instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and + func.hasRemoteFlowSource(output, sourceType) and + output.isParameterDeref(instr.getIndex()) + ) + } + + override string getSourceType() { result = sourceType } +} diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 8047bc384b2..23dda0ddb1e 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -19,7 +19,7 @@ private predicate wrapperFunctionStep( ) { not target.isVirtual() and not source.isVirtual() and - source.isDefined() and + source.hasDefinition() and exists(Call call, Expr arg, Parameter sourceParam | // there is a 'call' to 'target' with argument 'arg' at index 'targetParamIndex' target = resolveCall(call) and 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/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 1640bee0f35..989d36a0a9d 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1455,7 +1455,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 diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index d6ca4ebb768..282c13bfdbc 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -616,6 +616,7 @@ enumconstants( | 48 = _Float64x | 49 = _Float128 | 50 = _Float128x + | 51 = char8_t ; */ builtintypes( @@ -1142,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 @@ -1640,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 @@ -1738,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..49f84494fd7 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 +8811984 @location_stmt @@ -37,43 +37,43 @@ @diagnostic -68696 +68684 @file -60022 +60011 @folder -10945 +10943 @macroinvocation -35579091 +35573465 @function -3468206 +3467587 @fun_decl -3540511 +3539879 @var_decl -5359926 +5359112 @type_decl -1332120 +1331883 @namespace_decl -136867 +136842 @using -291435 +291383 @static_assert @@ -81,11 +81,11 @@ @parameter -4627839 +4627013 @membervariable -305681 +305626 @globalvariable @@ -101,23 +101,23 @@ @builtintype -504 +515 @derivedtype -4417712 +4416924 @decltype -47004 +46995 @usertype -4193822 +4193074 @mangledname -483674 +483588 @type_mention @@ -125,19 +125,19 @@ @routinetype -430474 +430397 @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 +390188 @frienddecl -240340 +240297 @comment -1580291 +1580009 @namespace -7687 +7686 @specialnamequalifyingelement @@ -205,7 +205,7 @@ @errorexpr -48715 +48706 @address_of @@ -213,7 +213,7 @@ @reference_to -1057881 +1058087 @indirect @@ -221,7 +221,7 @@ @ref_indirect -1253827 +1253933 @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 +226788 @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 +2265935 @type_operand @@ -661,15 +661,15 @@ @ctordirectinit -90192 +90175 @ctorvirtualinit -6229 +6228 @ctorfieldinit -196044 +196009 @ctordelegatinginit @@ -677,7 +677,7 @@ @dtordirectdestruct -29139 +29133 @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 +30997 @stmt_goto @@ -873,11 +873,11 @@ @stmt_return -1130186 +1130006 @stmt_block -1325091 +1324997 @stmt_end_test_while @@ -901,7 +901,7 @@ @stmt_try_block -17963 +17960 @stmt_microsoft_try @@ -909,7 +909,7 @@ @stmt_decl -613073 +613063 @stmt_set_vla_size @@ -949,39 +949,39 @@ @ppd_if -156092 +156064 @ppd_ifdef -61085 +61074 @ppd_ifndef -83326 +83311 @ppd_elif -20628 +20625 @ppd_else -57664 +57653 @ppd_endif -300505 +300451 @ppd_plain_include -290755 +290703 @ppd_define -318063 +318006 @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 +12094 @@ -1538,7 +1538,7 @@ 1 2 -9530 +9528 @@ -1554,7 +1554,7 @@ 4 5 -9530 +9528 @@ -1568,14 +1568,19 @@ 12 +2 +3 +10 + + 3 4 -3158 +2675 4 5 -6371 +6842 @@ -1621,8 +1626,8 @@ 12 -1233 -1234 +1103 +1104 10 @@ -1669,8 +1674,8 @@ 12 -8 -9 +7 +8 10 @@ -1679,13 +1684,13 @@ 10 -646 -647 +579 +580 10 -735 -736 +670 +671 10 @@ -1702,22 +1707,22 @@ 1 2 -9409 +7949 2 3 -2972 +2401 3 -9 -1019 +4 +932 -9 -615 -120 +4 +627 +811 @@ -1733,7 +1738,7 @@ 1 2 -13522 +12094 @@ -1749,12 +1754,12 @@ 1 2 -11679 +10285 2 3 -1831 +1798 3 @@ -1769,15 +1774,15 @@ diagnostic_for -847086 +846935 diagnostic -68696 +68684 compilation -9223 +9221 file_number @@ -1785,7 +1790,7 @@ file_number_diagnostic_number -6503 +6502 @@ -1799,12 +1804,12 @@ 1 2 -9256 +9254 2 3 -56742 +56732 254 @@ -1825,7 +1830,7 @@ 1 2 -68696 +68684 @@ -1841,7 +1846,7 @@ 1 2 -68696 +68684 @@ -1862,7 +1867,7 @@ 7 8 -5812 +5811 8 @@ -1898,7 +1903,7 @@ 1 2 -9223 +9221 @@ -1919,7 +1924,7 @@ 7 8 -5812 +5811 8 @@ -2013,7 +2018,7 @@ 5 6 -954 +953 7 @@ -2064,7 +2069,7 @@ 10 11 -954 +953 14 @@ -2099,7 +2104,7 @@ 254 255 -2621 +2620 309 @@ -2120,7 +2125,7 @@ 1 2 -6503 +6502 @@ -2130,19 +2135,19 @@ compilation_finished -9552 +9550 id -9552 +9550 cpu_seconds -8587 +8157 elapsed_seconds -219 +186 @@ -2156,7 +2161,7 @@ 1 2 -9552 +9550 @@ -2172,7 +2177,7 @@ 1 2 -9552 +9550 @@ -2188,17 +2193,17 @@ 1 2 -7797 +7160 2 3 -668 +756 3 -7 -120 +6 +241 @@ -2214,12 +2219,12 @@ 1 2 -8389 +7675 2 3 -197 +482 @@ -2235,71 +2240,66 @@ 1 2 -54 +32 2 3 +10 + + +3 +4 32 -5 -6 +7 +8 10 -6 -7 +8 +9 10 -9 -10 +21 +22 10 -11 -12 +26 +27 10 -16 -17 +31 +32 10 -37 -38 +104 +105 10 -52 -53 +137 +138 10 -78 -79 +144 +145 10 -91 -92 +173 +174 10 -156 -157 -10 - - -166 -167 -10 - - -233 -234 +206 +207 10 @@ -2316,66 +2316,66 @@ 1 2 -54 +32 2 3 +10 + + +3 +4 32 -5 -6 +7 +8 10 -6 -7 +8 +9 10 -9 -10 +21 +22 10 -11 -12 +25 +26 10 -16 -17 +29 +30 10 -36 -37 +84 +85 10 -51 -52 +122 +123 10 -74 -75 -21 - - -147 -148 +132 +133 10 -157 -158 +150 +151 10 -204 -205 +196 +197 10 @@ -5279,11 +5279,11 @@ header_to_external_package -8532 +8530 fileid -8532 +8530 package @@ -5301,7 +5301,7 @@ 1 2 -8532 +8530 @@ -6570,31 +6570,31 @@ locations_default -8813337 +8811984 id -8813337 +8811984 container -70967 +70954 startLine -150630 +150604 startColumn -5461 +5460 endLine -150455 +150428 endColumn -10626 +10625 @@ -6608,7 +6608,7 @@ 1 2 -8813337 +8811984 @@ -6624,7 +6624,7 @@ 1 2 -8813337 +8811984 @@ -6640,7 +6640,7 @@ 1 2 -8813337 +8811984 @@ -6656,7 +6656,7 @@ 1 2 -8813337 +8811984 @@ -6672,7 +6672,7 @@ 1 2 -8813337 +8811984 @@ -6688,62 +6688,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 +6759,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 +6830,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,62 +6901,62 @@ 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 9356 -2818 +2817 @@ -6972,57 +6972,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 +5635 69 91 -5329 +5328 91 @@ -7043,52 +7043,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 +7104,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 +7155,52 @@ 1 2 -31957 +31951 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 +7216,22 @@ 1 2 -112970 +112950 2 3 -17415 +17412 3 7 -12535 +12532 7 184 -7709 +7708 @@ -7247,52 +7247,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 +7613,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 +7674,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 +7725,22 @@ 1 2 -112180 +112160 2 3 -17250 +17247 3 7 -12074 +12072 7 46 -8949 +8947 @@ -7756,57 +7756,57 @@ 1 2 -31650 +31644 2 3 -17941 +17938 3 4 -19740 +19736 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 +7822,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 +7883,7 @@ 1 2 -4211 +4210 2 @@ -7898,7 +7898,7 @@ 4 5 -647 +646 5 @@ -7921,7 +7921,7 @@ 800 -7760 +7763 25755 526 @@ -7939,17 +7939,17 @@ 1 2 -4836 +4835 2 3 -1283 +1282 3 4 -954 +953 4 @@ -7990,7 +7990,7 @@ 1 2 -4244 +4243 2 @@ -8005,7 +8005,7 @@ 4 5 -636 +635 5 @@ -8046,7 +8046,7 @@ 1 2 -4869 +4868 2 @@ -8056,7 +8056,7 @@ 3 4 -943 +942 4 @@ -8097,7 +8097,7 @@ 1 2 -4244 +4243 2 @@ -8112,7 +8112,7 @@ 4 5 -636 +635 5 @@ -11616,23 +11616,23 @@ numlines -499247 +499158 element_id -492283 +492196 num_lines -9343 +9342 num_code -7293 +7291 num_comment -3937 +3936 @@ -11646,12 +11646,12 @@ 1 2 -485396 +485310 2 7 -6887 +6886 @@ -11667,12 +11667,12 @@ 1 2 -485451 +485364 2 7 -6832 +6831 @@ -11688,7 +11688,7 @@ 1 2 -492207 +492119 2 @@ -11709,7 +11709,7 @@ 1 2 -4255 +4254 2 @@ -11765,7 +11765,7 @@ 2 3 -1261 +1260 3 @@ -11811,12 +11811,12 @@ 1 2 -4310 +4309 2 3 -1261 +1260 3 @@ -11857,7 +11857,7 @@ 1 2 -3180 +3179 2 @@ -11892,7 +11892,7 @@ 101 7978 -329 +328 @@ -11908,7 +11908,7 @@ 1 2 -3202 +3201 2 @@ -11918,7 +11918,7 @@ 3 4 -636 +635 4 @@ -11928,7 +11928,7 @@ 6 10 -636 +635 10 @@ -11959,7 +11959,7 @@ 1 2 -3191 +3190 2 @@ -11969,7 +11969,7 @@ 3 4 -636 +635 4 @@ -11994,7 +11994,7 @@ 27 34 -318 +317 @@ -12010,7 +12010,7 @@ 1 2 -1886 +1885 2 @@ -12025,12 +12025,12 @@ 4 7 -329 +328 7 13 -329 +328 14 @@ -12061,7 +12061,7 @@ 1 2 -1897 +1896 2 @@ -12081,7 +12081,7 @@ 7 13 -329 +328 13 @@ -12112,7 +12112,7 @@ 1 2 -1897 +1896 2 @@ -12127,7 +12127,7 @@ 4 7 -329 +328 7 @@ -12157,11 +12157,11 @@ diagnostics -68696 +68684 id -68696 +68684 severity @@ -12177,7 +12177,7 @@ full_error_message -59484 +59474 location @@ -12195,7 +12195,7 @@ 1 2 -68696 +68684 @@ -12211,7 +12211,7 @@ 1 2 -68696 +68684 @@ -12227,7 +12227,7 @@ 1 2 -68696 +68684 @@ -12243,7 +12243,7 @@ 1 2 -68696 +68684 @@ -12259,7 +12259,7 @@ 1 2 -68696 +68684 @@ -12675,7 +12675,7 @@ 1 2 -59473 +59463 841 @@ -12696,7 +12696,7 @@ 1 2 -59484 +59474 @@ -12712,7 +12712,7 @@ 1 2 -59484 +59474 @@ -12728,7 +12728,7 @@ 1 2 -59484 +59474 @@ -12744,7 +12744,7 @@ 1 2 -59484 +59474 @@ -12854,19 +12854,19 @@ files -60022 +60011 id -60022 +60011 name -60022 +60011 simple -41060 +41052 ext @@ -12888,7 +12888,7 @@ 1 2 -60022 +60011 @@ -12904,7 +12904,7 @@ 1 2 -60022 +60011 @@ -12920,7 +12920,7 @@ 1 2 -60022 +60011 @@ -12936,7 +12936,7 @@ 1 2 -60022 +60011 @@ -12952,7 +12952,7 @@ 1 2 -60022 +60011 @@ -12968,7 +12968,7 @@ 1 2 -60022 +60011 @@ -12984,7 +12984,7 @@ 1 2 -60022 +60011 @@ -13000,7 +13000,7 @@ 1 2 -60022 +60011 @@ -13016,17 +13016,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13047,17 +13047,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13078,12 +13078,12 @@ 1 2 -36706 +36699 2 3 -3783 +3782 3 @@ -13104,7 +13104,7 @@ 1 2 -41060 +41052 @@ -13362,19 +13362,19 @@ folders -10945 +10943 id -10945 +10943 name -10945 +10943 simple -3136 +3135 @@ -13388,7 +13388,7 @@ 1 2 -10945 +10943 @@ -13404,7 +13404,7 @@ 1 2 -10945 +10943 @@ -13420,7 +13420,7 @@ 1 2 -10945 +10943 @@ -13436,7 +13436,7 @@ 1 2 -10945 +10943 @@ -13518,15 +13518,15 @@ containerparent -70945 +70932 parent -10945 +10943 child -70945 +70932 @@ -13591,7 +13591,7 @@ 1 2 -70945 +70932 @@ -13601,11 +13601,11 @@ fileannotations -5150534 +5149615 id -4825 +4824 kind @@ -13613,11 +13613,11 @@ name -54626 +54616 value -44646 +44638 @@ -13852,42 +13852,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 +13897,12 @@ 129 236 -4156 +4155 236 395 -4112 +4111 395 @@ -13923,7 +13923,7 @@ 1 2 -54626 +54616 @@ -13939,12 +13939,12 @@ 1 2 -9979 +9978 2 3 -8049 +8048 3 @@ -13954,42 +13954,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 +14010,7 @@ 1 2 -6898 +6896 2 @@ -14020,7 +14020,7 @@ 5 8 -3235 +3234 8 @@ -14040,17 +14040,17 @@ 25 40 -3235 +3234 40 195 -3520 +3519 195 207 -3509 +3508 207 @@ -14065,12 +14065,12 @@ 328 407 -3838 +3837 407 441 -1283 +1282 @@ -14086,7 +14086,7 @@ 1 2 -44635 +44627 2 @@ -14107,12 +14107,12 @@ 1 2 -6920 +6918 2 5 -2511 +2510 5 @@ -14122,7 +14122,7 @@ 8 16 -3498 +3497 16 @@ -14137,17 +14137,17 @@ 21 31 -3882 +3881 31 41 -3531 +3530 41 54 -3531 +3530 54 @@ -14458,19 +14458,19 @@ macroinvocations -35579091 +35573465 id -35579091 +35573465 macro_id -81232 +81217 location -761215 +761079 kind @@ -14488,7 +14488,7 @@ 1 2 -35579091 +35573465 @@ -14504,7 +14504,7 @@ 1 2 -35579091 +35573465 @@ -14520,7 +14520,7 @@ 1 2 -35579091 +35573465 @@ -14536,52 +14536,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 +14597,32 @@ 1 2 -43220 +43212 2 3 -10747 +10745 3 4 -5340 +5339 4 6 -6974 +6973 6 13 -6722 +6721 13 66 -6108 +6107 66 @@ -14643,12 +14643,12 @@ 1 2 -75090 +75077 2 3 -6141 +6140 @@ -14664,42 +14664,42 @@ 1 2 -284263 +284332 2 3 -177631 +177479 3 4 -43451 +43443 4 5 -58596 +58585 5 8 -63575 +63563 8 17 -61162 +61151 17 80 -57159 +57149 80 258137 -15375 +15372 @@ -14715,12 +14715,12 @@ 1 2 -712510 +712383 2 354 -48704 +48695 @@ -14736,7 +14736,7 @@ 1 2 -761215 +761079 @@ -14755,8 +14755,8 @@ 10 -3216528 -3216529 +3216594 +3216595 10 @@ -14809,15 +14809,15 @@ macroparent -31702256 +31697444 id -31702256 +31697444 parent_id -24679337 +24675437 @@ -14831,7 +14831,7 @@ 1 2 -31702256 +31697444 @@ -14847,17 +14847,17 @@ 1 2 -18989054 +18985994 2 3 -4852979 +4852266 3 88 -837303 +837176 @@ -14945,11 +14945,11 @@ macro_argument_unexpanded -92645581 +92630091 invocation -27418856 +27414544 argument_index @@ -14957,7 +14957,7 @@ text -312667 +312611 @@ -14971,22 +14971,22 @@ 1 2 -7656282 +7655047 2 3 -11466261 +11464654 3 4 -6261232 +6260126 4 67 -2035079 +2034716 @@ -15002,22 +15002,22 @@ 1 2 -7724233 +7722986 2 3 -11620160 +11618525 3 4 -6089819 +6088743 4 67 -1984642 +1984288 @@ -15033,7 +15033,7 @@ 50787 50788 -636 +635 50989 @@ -15041,8 +15041,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15059,7 +15059,7 @@ 2 3 -636 +635 13 @@ -15085,57 +15085,57 @@ 1 2 -37901 +37894 2 3 -61162 +61118 3 4 -14092 +14089 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 +15151,17 @@ 1 2 -226061 +226021 2 3 -76307 +76294 3 9 -10297 +10296 @@ -15171,11 +15171,11 @@ macro_argument_expanded -92645581 +92630091 invocation -27418856 +27414544 argument_index @@ -15183,7 +15183,7 @@ text -189442 +189409 @@ -15197,22 +15197,22 @@ 1 2 -7656282 +7655047 2 3 -11466261 +11464654 3 4 -6261232 +6260126 4 67 -2035079 +2034716 @@ -15228,22 +15228,22 @@ 1 2 -11164682 +11162952 2 3 -9894184 +9892725 3 4 -5269679 +5268749 4 9 -1090310 +1090116 @@ -15259,7 +15259,7 @@ 50787 50788 -636 +635 50989 @@ -15267,8 +15267,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15311,62 +15311,62 @@ 1 2 -22866 +22861 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 +15382,17 @@ 1 2 -95631 +95614 2 3 -79488 +79474 3 6 -14246 +14243 6 @@ -15407,15 +15407,15 @@ functions -3468206 +3467587 id -3468206 +3467587 name -288386 +288335 kind @@ -15433,7 +15433,7 @@ 1 2 -3468206 +3467587 @@ -15449,7 +15449,7 @@ 1 2 -3468206 +3467587 @@ -15465,27 +15465,27 @@ 1 2 -195397 +195363 2 3 -28316 +28311 3 5 -26079 +26074 5 13 -22164 +22160 13 123517 -16428 +16425 @@ -15501,7 +15501,7 @@ 1 2 -286927 +286876 2 @@ -15608,15 +15608,15 @@ function_entry_point -1008530 +1008372 id -1005602 +1005444 entry_point -1008530 +1008372 @@ -15630,7 +15630,7 @@ 1 2 -1002948 +1002791 2 @@ -15651,7 +15651,7 @@ 1 2 -1008530 +1008372 @@ -15661,15 +15661,15 @@ function_return_type -3478372 +3477751 id -3467734 +3467115 return_type -1023555 +1023372 @@ -15683,12 +15683,12 @@ 1 2 -3457590 +3456973 2 6 -10144 +10142 @@ -15704,17 +15704,17 @@ 1 2 -299156 +299102 2 3 -662688 +662569 3 84263 -61710 +61699 @@ -15735,49 +15735,49 @@ function_deleted -56183 +56173 id -56183 +56173 function_defaulted -12930 +12927 id -12930 +12927 fun_decls -3543779 +3543146 id -3540511 +3539879 function -3374756 +3374154 type_id -1010482 +1010302 name -256834 +256788 location -795431 +795290 @@ -15791,7 +15791,7 @@ 1 2 -3540511 +3539879 @@ -15807,12 +15807,12 @@ 1 2 -3537528 +3536896 2 4 -2983 +2982 @@ -15828,7 +15828,7 @@ 1 2 -3540511 +3539879 @@ -15844,7 +15844,7 @@ 1 2 -3540511 +3539879 @@ -15860,12 +15860,12 @@ 1 2 -3238733 +3238156 2 9 -136022 +135998 @@ -15881,12 +15881,12 @@ 1 2 -3358098 +3357498 2 6 -16658 +16655 @@ -15902,7 +15902,7 @@ 1 2 -3374756 +3374154 @@ -15918,12 +15918,12 @@ 1 2 -3287120 +3286533 2 9 -87636 +87621 @@ -15939,17 +15939,17 @@ 1 2 -280325 +280275 2 3 -661065 +660947 3 89606 -69091 +69079 @@ -15965,17 +15965,17 @@ 1 2 -292159 +292107 2 3 -657413 +657295 3 83378 -60910 +60899 @@ -15991,12 +15991,12 @@ 1 2 -943946 +943777 2 7512 -66536 +66524 @@ -16012,17 +16012,17 @@ 1 2 -913085 +912922 2 6 -80146 +80132 6 22467 -17250 +17247 @@ -16038,32 +16038,32 @@ 1 2 -153548 +153520 2 3 -29303 +29298 3 4 -15934 +15932 4 6 -19521 +19517 6 13 -20201 +20197 13 123766 -18325 +18322 @@ -16079,32 +16079,32 @@ 1 2 -164175 +164145 2 3 -28481 +28476 3 4 -14454 +14451 4 7 -21637 +21633 7 25 -19641 +19638 25 123501 -8444 +8443 @@ -16120,17 +16120,17 @@ 1 2 -224328 +224288 2 5 -20870 +20866 5 63265 -11635 +11633 @@ -16146,27 +16146,27 @@ 1 2 -164668 +164639 2 3 -43461 +43454 3 4 -16439 +16436 4 8 -20573 +20570 8 8921 -11690 +11688 @@ -16182,27 +16182,27 @@ 1 2 -522750 +522656 2 3 -143886 +143860 3 5 -64858 +64846 5 125 -59693 +59682 125 3043 -4244 +4243 @@ -16218,22 +16218,22 @@ 1 2 -537676 +537580 2 3 -156849 +156821 3 9 -64343 +64331 9 3043 -36563 +36557 @@ -16249,17 +16249,17 @@ 1 2 -701785 +701660 2 4 -61787 +61776 4 1522 -31858 +31853 @@ -16275,12 +16275,12 @@ 1 2 -770427 +770289 2 134 -25004 +25000 @@ -16290,11 +16290,11 @@ fun_def -1230764 +1230544 id -1230764 +1230544 @@ -16517,26 +16517,26 @@ fun_decl_empty_throws -1420942 +1420688 fun_decl -1420942 +1420688 fun_decl_noexcept -32911 +32905 fun_decl -32122 +32116 constant -32791 +32785 @@ -16550,7 +16550,7 @@ 1 2 -31332 +31326 2 @@ -16571,7 +16571,7 @@ 1 2 -32670 +32664 2 @@ -16586,11 +16586,11 @@ fun_decl_empty_noexcept -391947 +391877 fun_decl -391947 +391877 @@ -16645,11 +16645,11 @@ param_decl_bind -4651385 +4650555 id -4651385 +4650555 index @@ -16657,7 +16657,7 @@ fun_decl -3071663 +3071115 @@ -16671,7 +16671,7 @@ 1 2 -4651385 +4650555 @@ -16687,7 +16687,7 @@ 1 2 -4651385 +4650555 @@ -16785,22 +16785,22 @@ 1 2 -2195218 +2194827 2 3 -478564 +478478 3 4 -242709 +242665 4 65 -155171 +155143 @@ -16816,22 +16816,22 @@ 1 2 -2195218 +2194827 2 3 -478564 +478478 3 4 -242709 +242665 4 65 -155171 +155143 @@ -16841,27 +16841,27 @@ var_decls -5368776 +5367960 id -5359926 +5359112 variable -5132044 +5131248 type_id -2007706 +2007358 name -126306 +126283 location -1232409 +1232189 @@ -16875,7 +16875,7 @@ 1 2 -5359926 +5359112 @@ -16891,12 +16891,12 @@ 1 2 -5351262 +5350449 2 4 -8663 +8662 @@ -16912,7 +16912,7 @@ 1 2 -5359926 +5359112 @@ -16928,7 +16928,7 @@ 1 2 -5359882 +5359068 2 @@ -16949,12 +16949,12 @@ 1 2 -4944542 +4943758 2 9 -187501 +187490 @@ -16970,12 +16970,12 @@ 1 2 -5096697 +5095886 2 7 -35346 +35362 @@ -16991,12 +16991,12 @@ 1 2 -5114475 +5113682 2 3 -17569 +17565 @@ -17012,12 +17012,12 @@ 1 2 -5023833 +5023057 2 9 -108210 +108191 @@ -17033,22 +17033,22 @@ 1 2 -1580818 +1580525 2 3 -228879 +228861 3 11 -156958 +156941 11 5924 -41049 +41030 @@ -17064,22 +17064,22 @@ 1 2 -1605011 +1604713 2 3 -219645 +219628 3 13 -151135 +151108 13 5424 -31913 +31908 @@ -17095,17 +17095,17 @@ 1 2 -1832849 +1832533 2 5 -151245 +151218 5 772 -23611 +23607 @@ -17121,17 +17121,17 @@ 1 2 -1758460 +1758157 2 4 -154469 +154441 4 3608 -94776 +94759 @@ -17147,42 +17147,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 +17198,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 +17244,32 @@ 1 2 -76307 +76294 2 3 -16889 +16886 3 4 -8861 +8848 4 7 -10473 +10482 7 27 -9519 +9517 27 125807 -4255 +4254 @@ -17285,32 +17285,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 +17326,22 @@ 1 2 -892478 +892231 2 3 -149062 +149123 3 6 -113420 +113388 6 128450 -77448 +77445 @@ -17357,22 +17357,22 @@ 1 2 -941237 +940981 2 3 -114483 +114551 3 6 -102661 +102632 6 128224 -74026 +74024 @@ -17388,17 +17388,17 @@ 1 2 -1055370 +1055160 2 3 -85092 +85099 3 118388 -91946 +91930 @@ -17414,12 +17414,12 @@ 1 2 -1223438 +1223220 2 52 -8970 +8969 @@ -17429,11 +17429,11 @@ var_def -2437456 +2437164 id -2437456 +2437164 @@ -17503,19 +17503,19 @@ type_decls -1332120 +1331883 id -1332120 +1331883 type_id -1300371 +1300139 location -1086812 +1086618 @@ -17529,7 +17529,7 @@ 1 2 -1332120 +1331883 @@ -17545,7 +17545,7 @@ 1 2 -1332120 +1331883 @@ -17561,12 +17561,12 @@ 1 2 -1277275 +1277047 2 24 -23096 +23092 @@ -17582,12 +17582,12 @@ 1 2 -1278569 +1278341 2 24 -21802 +21798 @@ -17603,12 +17603,12 @@ 1 2 -1031352 +1031168 2 506 -55459 +55449 @@ -17624,12 +17624,12 @@ 1 2 -1032833 +1032648 2 506 -53979 +53969 @@ -17639,45 +17639,45 @@ type_def -937716 +937549 id -937716 +937549 type_decl_top -268689 +268642 type_decl -268689 +268642 namespace_decls -136867 +136842 id -136867 +136842 namespace_id -7676 +7675 location -122248 +122226 bodylocation -122577 +122555 @@ -17691,7 +17691,7 @@ 1 2 -136867 +136842 @@ -17707,7 +17707,7 @@ 1 2 -136867 +136842 @@ -17723,7 +17723,7 @@ 1 2 -136867 +136842 @@ -17739,7 +17739,7 @@ 1 2 -3619 +3618 2 @@ -17754,7 +17754,7 @@ 4 7 -647 +646 7 @@ -17790,7 +17790,7 @@ 1 2 -3619 +3618 2 @@ -17805,7 +17805,7 @@ 4 7 -647 +646 7 @@ -17841,7 +17841,7 @@ 1 2 -3619 +3618 2 @@ -17856,7 +17856,7 @@ 4 7 -647 +646 7 @@ -17892,12 +17892,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17913,12 +17913,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17934,7 +17934,7 @@ 1 2 -121502 +121481 2 @@ -17955,12 +17955,12 @@ 1 2 -114560 +114540 2 11 -8016 +8015 @@ -17976,12 +17976,12 @@ 1 2 -114560 +114540 2 9 -8016 +8015 @@ -17997,7 +17997,7 @@ 1 2 -122182 +122160 2 @@ -18012,19 +18012,19 @@ usings -291435 +291383 id -291435 +291383 element_id -46401 +46392 location -23864 +23859 @@ -18038,7 +18038,7 @@ 1 2 -291435 +291383 @@ -18054,7 +18054,7 @@ 1 2 -291435 +291383 @@ -18070,7 +18070,7 @@ 1 2 -39393 +39386 2 @@ -18080,7 +18080,7 @@ 4 127 -3257 +3256 @@ -18096,7 +18096,7 @@ 1 2 -39393 +39386 2 @@ -18106,7 +18106,7 @@ 4 127 -3257 +3256 @@ -18122,12 +18122,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18153,12 +18153,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18178,15 +18178,15 @@ using_container -458088 +458007 parent -11230 +11228 child -291435 +291383 @@ -18200,12 +18200,12 @@ 1 2 -3213 +3212 2 4 -943 +942 4 @@ -18230,7 +18230,7 @@ 178 179 -1261 +1260 179 @@ -18256,17 +18256,17 @@ 1 2 -215851 +215812 2 3 -50371 +50362 3 11 -23140 +23136 13 @@ -18647,15 +18647,15 @@ params -4644903 +4644074 id -4627839 +4627013 function -3043840 +3043297 index @@ -18663,7 +18663,7 @@ type_id -1856790 +1856458 @@ -18677,7 +18677,7 @@ 1 2 -4627170 +4626344 2 @@ -18698,7 +18698,7 @@ 1 2 -4627839 +4627013 @@ -18714,12 +18714,12 @@ 1 2 -4612792 +4611969 2 4 -15046 +15043 @@ -18735,22 +18735,22 @@ 1 2 -2166606 +2166219 2 3 -475109 +475024 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18766,22 +18766,22 @@ 1 2 -2166606 +2166219 2 3 -475109 +475024 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18797,22 +18797,22 @@ 1 2 -2283184 +2282777 2 3 -470964 +470880 3 5 -254323 +254277 5 20 -35368 +35362 @@ -18951,22 +18951,22 @@ 1 2 -1504718 +1504450 2 3 -186712 +186678 3 14 -139488 +139463 14 5175 -25871 +25866 @@ -18982,22 +18982,22 @@ 1 2 -1524579 +1524307 2 3 -179846 +179814 3 23 -139718 +139693 23 4690 -12644 +12642 @@ -19013,12 +19013,12 @@ 1 2 -1745102 +1744791 2 65 -111687 +111667 @@ -19116,19 +19116,19 @@ membervariables -310298 +310243 id -305681 +305626 type_id -132919 +132895 name -53222 +53213 @@ -19142,12 +19142,12 @@ 1 2 -301217 +301164 2 7 -4463 +4462 @@ -19163,7 +19163,7 @@ 1 2 -305681 +305626 @@ -19179,22 +19179,22 @@ 1 2 -108068 +108048 2 3 -12272 +12269 3 9 -10056 +10054 9 1712 -2522 +2521 @@ -19210,17 +19210,17 @@ 1 2 -115119 +115099 2 3 -9091 +9089 3 266 -8707 +8706 @@ -19236,17 +19236,17 @@ 1 2 -28097 +28092 2 3 -8170 +8168 3 4 -5373 +5372 4 @@ -19256,12 +19256,12 @@ 6 15 -4090 +4089 15 1967 -3476 +3475 @@ -19277,12 +19277,12 @@ 1 2 -34293 +34287 2 3 -6854 +6853 3 @@ -19292,7 +19292,7 @@ 4 7 -4299 +4298 7 @@ -20844,19 +20844,19 @@ builtintypes -504 +515 id -504 +515 name -504 +515 kind -504 +515 size @@ -20882,7 +20882,7 @@ 1 2 -504 +515 @@ -20898,7 +20898,7 @@ 1 2 -504 +515 @@ -20914,7 +20914,7 @@ 1 2 -504 +515 @@ -20930,7 +20930,7 @@ 1 2 -504 +515 @@ -20946,7 +20946,7 @@ 1 2 -504 +515 @@ -20962,7 +20962,7 @@ 1 2 -504 +515 @@ -20978,7 +20978,7 @@ 1 2 -504 +515 @@ -20994,7 +20994,7 @@ 1 2 -504 +515 @@ -21010,7 +21010,7 @@ 1 2 -504 +515 @@ -21026,7 +21026,7 @@ 1 2 -504 +515 @@ -21042,7 +21042,7 @@ 1 2 -504 +515 @@ -21058,7 +21058,7 @@ 1 2 -504 +515 @@ -21074,7 +21074,7 @@ 1 2 -504 +515 @@ -21090,7 +21090,7 @@ 1 2 -504 +515 @@ -21106,7 +21106,7 @@ 1 2 -504 +515 @@ -21135,8 +21135,8 @@ 10 -6 -7 +7 +8 10 @@ -21181,8 +21181,8 @@ 10 -6 -7 +7 +8 10 @@ -21227,8 +21227,8 @@ 10 -6 -7 +7 +8 10 @@ -21310,8 +21310,8 @@ 10 -28 -29 +29 +30 10 @@ -21336,8 +21336,8 @@ 10 -28 -29 +29 +30 10 @@ -21362,8 +21362,8 @@ 10 -28 -29 +29 +30 10 @@ -21420,8 +21420,8 @@ 10 -7 -8 +8 +9 10 @@ -21456,8 +21456,8 @@ 10 -7 -8 +8 +9 10 @@ -21492,8 +21492,8 @@ 10 -7 -8 +8 +9 10 @@ -21556,15 +21556,15 @@ derivedtypes -4417712 +4416924 id -4417712 +4416924 name -2172605 +2172217 kind @@ -21572,7 +21572,7 @@ type_id -2606150 +2605685 @@ -21586,7 +21586,7 @@ 1 2 -4417712 +4416924 @@ -21602,7 +21602,7 @@ 1 2 -4417712 +4416924 @@ -21618,7 +21618,7 @@ 1 2 -4417712 +4416924 @@ -21634,17 +21634,17 @@ 1 2 -1570509 +1570229 2 3 -487524 +487437 3 45177 -114571 +114551 @@ -21660,7 +21660,7 @@ 1 2 -2172572 +2172184 2 @@ -21681,17 +21681,17 @@ 1 2 -1570750 +1570470 2 3 -487293 +487206 3 45159 -114560 +114540 @@ -21860,22 +21860,22 @@ 1 2 -1546239 +1545963 2 3 -372700 +372633 3 4 -633867 +633753 4 202 -53343 +53333 @@ -21891,22 +21891,22 @@ 1 2 -1547456 +1547180 2 3 -372546 +372480 3 4 -632803 +632690 4 198 -53343 +53333 @@ -21922,22 +21922,22 @@ 1 2 -1547774 +1547498 2 3 -373829 +373763 3 4 -632759 +632646 4 7 -51785 +51776 @@ -21947,11 +21947,11 @@ pointerishsize -3331733 +3331139 id -3331733 +3331139 size @@ -21973,7 +21973,7 @@ 1 2 -3331733 +3331139 @@ -21989,7 +21989,7 @@ 1 2 -3331733 +3331139 @@ -22068,11 +22068,11 @@ arraysizes -17196 +17193 id -17196 +17193 num_elements @@ -22080,7 +22080,7 @@ bytesize -2511 +2510 alignment @@ -22098,7 +22098,7 @@ 1 2 -17196 +17193 @@ -22114,7 +22114,7 @@ 1 2 -17196 +17193 @@ -22130,7 +22130,7 @@ 1 2 -17196 +17193 @@ -22151,7 +22151,7 @@ 2 3 -1272 +1271 3 @@ -22192,7 +22192,7 @@ 1 2 -1590 +1589 2 @@ -22228,7 +22228,7 @@ 1 2 -1590 +1589 2 @@ -22315,7 +22315,7 @@ 1 2 -1908 +1907 2 @@ -22346,7 +22346,7 @@ 1 2 -1952 +1951 2 @@ -22504,15 +22504,15 @@ typedefbase -1819645 +1819320 id -1819645 +1819320 type_id -847360 +847209 @@ -22526,7 +22526,7 @@ 1 2 -1819645 +1819320 @@ -22542,22 +22542,22 @@ 1 2 -656634 +656517 2 3 -87910 +87895 3 6 -69596 +69583 6 5503 -33218 +33212 @@ -22567,19 +22567,19 @@ decltypes -47004 +46995 id -47004 +46995 expr -43440 +43432 base_type -8630 +8629 parentheses_would_change_meaning @@ -22597,7 +22597,7 @@ 1 2 -47004 +46995 @@ -22613,7 +22613,7 @@ 1 2 -47004 +46995 @@ -22629,7 +22629,7 @@ 1 2 -47004 +46995 @@ -22645,12 +22645,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22666,12 +22666,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22687,7 +22687,7 @@ 1 2 -43440 +43432 @@ -22703,12 +22703,12 @@ 1 2 -5823 +5822 2 3 -2522 +2521 3 @@ -22729,12 +22729,12 @@ 1 2 -2314 +2313 2 3 -5702 +5701 3 @@ -22755,7 +22755,7 @@ 1 2 -8630 +8629 @@ -22828,15 +22828,15 @@ usertypes -4193822 +4193074 id -4193822 +4193074 name -879383 +879226 kind @@ -22854,7 +22854,7 @@ 1 2 -4193822 +4193074 @@ -22870,7 +22870,7 @@ 1 2 -4193822 +4193074 @@ -22886,22 +22886,22 @@ 1 2 -577453 +577350 2 3 -194794 +194759 3 7 -69311 +69298 7 32744 -37824 +37818 @@ -22917,12 +22917,12 @@ 1 2 -826742 +826595 2 10 -52641 +52631 @@ -23059,11 +23059,11 @@ usertypesize -1386571 +1386324 id -1386571 +1386324 size @@ -23085,7 +23085,7 @@ 1 2 -1386571 +1386324 @@ -23101,7 +23101,7 @@ 1 2 -1386571 +1386324 @@ -23354,15 +23354,15 @@ mangled_name -4190543 +4189795 id -4190543 +4189795 mangled_name -483674 +483588 @@ -23376,7 +23376,7 @@ 1 2 -4190543 +4189795 @@ -23392,32 +23392,32 @@ 1 2 -292082 +292030 2 3 -62292 +62281 3 4 -33339 +33333 4 7 -36969 +36962 7 24 -37068 +37061 24 8580 -21922 +21918 @@ -23427,59 +23427,59 @@ is_pod_class -589209 +589104 id -589209 +589104 is_standard_layout_class -1159183 +1158976 id -1159183 +1158976 is_complete -1365065 +1364822 id -1365065 +1364822 is_class_template -225348 +225308 id -225348 +225308 class_instantiation -1157790 +1157583 to -1156222 +1156015 from -68027 +68015 @@ -23493,7 +23493,7 @@ 1 2 -1154741 +1154535 2 @@ -23514,47 +23514,47 @@ 1 2 -19959 +19956 2 3 -11997 +11995 3 4 -6854 +6853 4 5 -4617 +4616 5 7 -5637 +5635 7 11 -6053 +6052 11 20 -5198 +5197 20 84 -5110 +5109 84 4845 -2599 +2598 @@ -23564,11 +23564,11 @@ class_template_argument -3035999 +3035457 type_id -1392811 +1392563 index @@ -23576,7 +23576,7 @@ arg_type -860904 +860750 @@ -23590,27 +23590,27 @@ 1 2 -567111 +567010 2 3 -433731 +433654 3 4 -244979 +244935 4 7 -122807 +122785 7 113 -24182 +24177 @@ -23626,22 +23626,22 @@ 1 2 -593344 +593238 2 3 -445959 +445879 3 4 -258435 +258389 4 113 -95072 +95055 @@ -23749,27 +23749,27 @@ 1 2 -522278 +522185 2 3 -187435 +187402 3 4 -56710 +56699 4 11 -67391 +67379 11 11852 -27088 +27083 @@ -23785,17 +23785,17 @@ 1 2 -746453 +746320 2 3 -95543 +95526 3 22 -18906 +18903 @@ -23805,11 +23805,11 @@ class_template_argument_value -345798 +345736 type_id -223846 +223806 index @@ -23817,7 +23817,7 @@ arg_value -328240 +328181 @@ -23831,17 +23831,17 @@ 1 2 -201484 +201448 2 3 -13708 +13706 3 14 -8652 +8651 @@ -23857,17 +23857,17 @@ 1 2 -189859 +189825 2 3 -16921 +16918 3 37 -16790 +16787 44 @@ -24010,12 +24010,12 @@ 1 2 -311000 +310944 2 4 -17240 +17236 @@ -24031,7 +24031,7 @@ 1 2 -328240 +328181 @@ -24041,15 +24041,15 @@ is_proxy_class_for -46379 +46370 id -46379 +46370 templ_param_id -46379 +46370 @@ -24063,7 +24063,7 @@ 1 2 -46379 +46370 @@ -24079,7 +24079,7 @@ 1 2 -46379 +46370 @@ -24395,26 +24395,26 @@ is_function_template -983756 +983580 id -983756 +983580 function_instantiation -708310 +708184 to -708310 +708184 from -129333 +129310 @@ -24428,7 +24428,7 @@ 1 2 -708310 +708184 @@ -24444,37 +24444,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 +24484,11 @@ function_template_argument -1910528 +1910187 function_id -1054361 +1054173 index @@ -24496,7 +24496,7 @@ arg_type -338450 +338390 @@ -24510,22 +24510,22 @@ 1 2 -583583 +583479 2 3 -291007 +290955 3 4 -127764 +127742 4 21 -52005 +51995 @@ -24541,22 +24541,22 @@ 1 2 -598005 +597898 2 3 -288693 +288642 3 4 -110941 +110921 4 21 -56720 +56710 @@ -24794,27 +24794,27 @@ 1 2 -226127 +226086 2 3 -45117 +45109 3 6 -27669 +27664 6 19 -25607 +25603 19 2030 -13928 +13925 @@ -24830,12 +24830,12 @@ 1 2 -314827 +314771 2 12 -23622 +23618 @@ -24845,11 +24845,11 @@ function_template_argument_value -198062 +198027 function_id -107081 +107062 index @@ -24857,7 +24857,7 @@ arg_value -170601 +170571 @@ -24871,12 +24871,12 @@ 1 2 -101564 +101546 2 14 -5516 +5515 @@ -24892,17 +24892,17 @@ 1 2 -84960 +84945 2 3 -16176 +16173 3 113 -5944 +5943 @@ -25030,12 +25030,12 @@ 1 2 -143644 +143619 2 3 -26452 +26447 3 @@ -25056,7 +25056,7 @@ 1 2 -170601 +170571 @@ -25066,26 +25066,26 @@ is_variable_template -17810 +17807 id -17810 +17807 variable_instantiation -35807 +35800 to -35807 +35800 from -6470 +6469 @@ -25099,7 +25099,7 @@ 1 2 -35807 +35800 @@ -25115,12 +25115,12 @@ 1 2 -2237 +2236 2 3 -1908 +1907 3 @@ -25507,15 +25507,15 @@ routinetypes -430474 +430397 id -430474 +430397 return_type -177565 +177533 @@ -25529,7 +25529,7 @@ 1 2 -430474 +430397 @@ -25545,17 +25545,17 @@ 1 2 -143107 +143082 2 3 -18128 +18125 3 9 -13324 +13322 9 @@ -25570,11 +25570,11 @@ routinetypeargs -719836 +719708 routine -351841 +351778 index @@ -25582,7 +25582,7 @@ type_id -205564 +205527 @@ -25596,27 +25596,27 @@ 1 2 -161926 +161897 2 3 -95949 +95932 3 4 -53935 +53925 4 6 -32330 +32324 6 33 -7698 +7697 @@ -25632,22 +25632,22 @@ 1 2 -186745 +186711 2 3 -96706 +96689 3 4 -47662 +47653 4 22 -20727 +20723 @@ -25805,27 +25805,27 @@ 1 2 -122412 +122391 2 3 -40840 +40833 3 4 -13215 +13212 4 7 -16636 +16633 7 1349 -12458 +12456 @@ -25841,17 +25841,17 @@ 1 2 -154107 +154079 2 3 -39437 +39430 3 33 -12019 +12017 @@ -25861,19 +25861,19 @@ ptrtomembers -12633 +12631 id -12633 +12631 type_id -9398 +9396 class_id -6360 +6359 @@ -25887,7 +25887,7 @@ 1 2 -12633 +12631 @@ -25903,7 +25903,7 @@ 1 2 -12633 +12631 @@ -25919,7 +25919,7 @@ 1 2 -9036 +9035 2 @@ -25940,7 +25940,7 @@ 1 2 -9036 +9035 2 @@ -25961,7 +25961,7 @@ 1 2 -5340 +5339 2 @@ -25987,7 +25987,7 @@ 1 2 -5340 +5339 2 @@ -26007,15 +26007,15 @@ specifiers -493 +504 id -493 +504 str -493 +504 @@ -26029,7 +26029,7 @@ 1 2 -493 +504 @@ -26045,7 +26045,7 @@ 1 2 -493 +504 @@ -26055,11 +26055,11 @@ typespecifiers -1331934 +1331696 type_id -1325069 +1324832 spec_id @@ -26077,12 +26077,12 @@ 1 2 -1318203 +1317968 2 3 -6865 +6864 @@ -26138,11 +26138,11 @@ funspecifiers -11102993 +11101011 func_id -3417758 +3417148 spec_id @@ -26160,27 +26160,27 @@ 1 2 -342311 +342249 2 3 -436988 +436910 3 4 -842710 +842560 4 5 -1677316 +1677016 5 8 -118431 +118410 @@ -26384,11 +26384,11 @@ attributes -413159 +413730 id -413159 +413730 kind @@ -26404,7 +26404,7 @@ location -89984 +90510 @@ -26418,7 +26418,7 @@ 1 2 -413159 +413730 @@ -26434,7 +26434,7 @@ 1 2 -413159 +413730 @@ -26450,7 +26450,7 @@ 1 2 -413159 +413730 @@ -26466,7 +26466,7 @@ 1 2 -413159 +413730 @@ -26480,8 +26480,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26528,8 +26528,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26579,12 +26579,12 @@ 4 -645 +648 780 4 -806 +807 1148 4 @@ -26594,7 +26594,7 @@ 4 -25877 +26224 35247 4 @@ -26678,11 +26678,11 @@ 440 -627 +628 4 -642 +645 776 4 @@ -26718,8 +26718,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26766,8 +26766,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26784,12 +26784,12 @@ 1 2 -26208 +26730 2 3 -5310 +5313 3 @@ -26798,13 +26798,8 @@ 4 -7 -6755 - - -7 8 -631 +7387 8 @@ -26830,7 +26825,7 @@ 1 2 -89984 +90510 @@ -26846,7 +26841,7 @@ 1 2 -27889 +28415 2 @@ -26882,7 +26877,7 @@ 1 2 -89984 +90510 @@ -26892,11 +26887,11 @@ attribute_args -152050 +152615 id -152050 +152615 kind @@ -26904,7 +26899,7 @@ attribute -150751 +151316 index @@ -26912,7 +26907,7 @@ location -56842 +57362 @@ -26926,7 +26921,7 @@ 1 2 -152050 +152615 @@ -26942,7 +26937,7 @@ 1 2 -152050 +152615 @@ -26958,7 +26953,7 @@ 1 2 -152050 +152615 @@ -26974,7 +26969,7 @@ 1 2 -152050 +152615 @@ -26993,8 +26988,8 @@ 1 -89512 -89513 +89859 +89860 1 @@ -27014,8 +27009,8 @@ 1 -89030 -89031 +89377 +89378 1 @@ -27056,8 +27051,8 @@ 1 -34672 -34673 +34991 +34992 1 @@ -27074,7 +27069,7 @@ 1 2 -149973 +150538 2 @@ -27095,7 +27090,7 @@ 1 2 -150261 +150826 2 @@ -27116,7 +27111,7 @@ 1 2 -149973 +150538 2 @@ -27137,7 +27132,7 @@ 1 2 -149978 +150543 2 @@ -27171,8 +27166,8 @@ 1 -92593 -92594 +92940 +92941 1 @@ -27223,8 +27218,8 @@ 1 -92608 -92609 +92955 +92956 1 @@ -27254,8 +27249,8 @@ 1 -34262 -34263 +34581 +34582 1 @@ -27272,17 +27267,17 @@ 1 2 -26779 +27295 2 3 -8446 +8429 3 5 -2865 +2886 5 @@ -27308,7 +27303,7 @@ 1 2 -51047 +51567 2 @@ -27329,17 +27324,17 @@ 1 2 -26765 +27281 2 3 -8463 +8445 3 5 -2863 +2884 5 @@ -27365,7 +27360,7 @@ 1 2 -56837 +57357 3 @@ -27380,11 +27375,11 @@ attribute_arg_value -152026 +152591 arg -152026 +152591 value @@ -27402,7 +27397,7 @@ 1 2 -152026 +152591 @@ -27432,7 +27427,7 @@ 10 -23973 +23976 133 @@ -27549,15 +27544,15 @@ typeattributes -19323 +19320 type_id -17941 +17938 spec_id -19323 +19320 @@ -27571,7 +27566,7 @@ 1 2 -17240 +17236 2 @@ -27592,7 +27587,7 @@ 1 2 -19323 +19320 @@ -27602,15 +27597,15 @@ funcattributes -304387 +304333 func_id -164240 +164211 spec_id -304387 +304333 @@ -27624,17 +27619,17 @@ 1 2 -89687 +89671 2 3 -12579 +12576 3 4 -59967 +59956 4 @@ -27655,7 +27650,7 @@ 1 2 -304387 +304333 @@ -27665,15 +27660,15 @@ varattributes -371203 +371224 var_id -322400 +322421 spec_id -371203 +371224 @@ -27687,7 +27682,7 @@ 1 2 -273633 +273654 2 @@ -27713,7 +27708,7 @@ 1 2 -371203 +371224 @@ -27771,15 +27766,15 @@ unspecifiedtype -9070084 +9068477 type_id -9070084 +9068477 unspecified_type_id -4976818 +4975940 @@ -27793,7 +27788,7 @@ 1 2 -9070084 +9068477 @@ -27809,17 +27804,17 @@ 1 2 -2709392 +2708920 2 3 -1952849 +1952501 3 7950 -314575 +314519 @@ -27829,11 +27824,11 @@ member -4921643 +4920765 parent -814481 +814336 index @@ -27841,7 +27836,7 @@ child -4906081 +4905205 @@ -27855,47 +27850,47 @@ 1 2 -42321 +42313 2 3 -223780 +223740 3 4 -204621 +204584 4 5 -86923 +86908 5 7 -65900 +65888 7 9 -61612 +61601 9 15 -62050 +62039 15 47 -61184 +61173 47 245 -6086 +6085 @@ -27911,47 +27906,47 @@ 1 2 -41663 +41655 2 3 -223604 +223564 3 4 -199378 +199343 4 5 -89731 +89715 5 7 -66371 +66360 7 9 -61689 +61678 9 15 -62972 +62960 15 42 -61272 +61261 42 281 -7797 +7796 @@ -28109,7 +28104,7 @@ 1 2 -4906081 +4905205 @@ -28125,12 +28120,12 @@ 1 2 -4890727 +4889854 2 7 -15353 +15350 @@ -28140,15 +28135,15 @@ enclosingfunction -125077 +125055 child -125077 +125055 parent -71405 +71392 @@ -28162,7 +28157,7 @@ 1 2 -125077 +125055 @@ -28178,22 +28173,22 @@ 1 2 -38340 +38333 2 3 -21078 +21074 3 4 -6536 +6535 4 7 -5373 +5372 7 @@ -28208,15 +28203,15 @@ derivations -390258 +390188 derivation -390258 +390188 sub -364442 +364377 index @@ -28224,11 +28219,11 @@ super -235701 +235659 location -86978 +86963 @@ -28242,7 +28237,7 @@ 1 2 -390258 +390188 @@ -28258,7 +28253,7 @@ 1 2 -390258 +390188 @@ -28274,7 +28269,7 @@ 1 2 -390258 +390188 @@ -28290,7 +28285,7 @@ 1 2 -390258 +390188 @@ -28306,12 +28301,12 @@ 1 2 -341872 +341811 2 7 -22569 +22565 @@ -28327,12 +28322,12 @@ 1 2 -351490 +351427 2 7 -12951 +12949 @@ -28348,12 +28343,12 @@ 1 2 -341883 +341822 2 7 -22558 +22554 @@ -28369,12 +28364,12 @@ 1 2 -351479 +351416 2 7 -12962 +12960 @@ -28554,12 +28549,12 @@ 1 2 -220917 +220878 2 1142 -14783 +14780 @@ -28575,12 +28570,12 @@ 1 2 -220928 +220889 2 1142 -14772 +14769 @@ -28596,7 +28591,7 @@ 1 2 -235251 +235209 2 @@ -28617,12 +28612,12 @@ 1 2 -228342 +228301 2 439 -7358 +7357 @@ -28638,22 +28633,22 @@ 1 2 -66349 +66338 2 3 -8389 +8388 3 7 -6613 +6611 7 795 -5626 +5625 @@ -28669,17 +28664,17 @@ 1 2 -68587 +68574 2 3 -6371 +6370 3 8 -7040 +7039 8 @@ -28700,7 +28695,7 @@ 1 2 -86956 +86941 2 @@ -28721,22 +28716,22 @@ 1 2 -69289 +69276 2 3 -8203 +8201 3 9 -6525 +6524 9 795 -2961 +2960 @@ -28746,11 +28741,11 @@ derspecifiers -392638 +392568 der_id -390225 +390155 spec_id @@ -28768,7 +28763,7 @@ 1 2 -387812 +387743 2 @@ -28814,11 +28809,11 @@ direct_base_offsets -310550 +310495 der_id -310550 +310495 offset @@ -28836,7 +28831,7 @@ 1 2 -310550 +310495 @@ -28922,11 +28917,11 @@ virtual_base_offsets -6338 +6337 sub -3509 +3508 super @@ -28979,7 +28974,7 @@ 1 2 -2961 +2960 2 @@ -29213,23 +29208,23 @@ frienddecls -240340 +240297 id -240340 +240297 type_id -27285 +27280 decl_id -49044 +49035 location -7303 +7302 @@ -29243,7 +29238,7 @@ 1 2 -240340 +240297 @@ -29259,7 +29254,7 @@ 1 2 -240340 +240297 @@ -29275,7 +29270,7 @@ 1 2 -240340 +240297 @@ -29291,17 +29286,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29311,7 +29306,7 @@ 6 8 -2314 +2313 8 @@ -29342,17 +29337,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29362,7 +29357,7 @@ 6 8 -2314 +2313 8 @@ -29393,12 +29388,12 @@ 1 2 -25706 +25701 2 31 -1579 +1578 @@ -29414,7 +29409,7 @@ 1 2 -33690 +33684 2 @@ -29429,12 +29424,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29450,7 +29445,7 @@ 1 2 -33690 +33684 2 @@ -29465,12 +29460,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29486,7 +29481,7 @@ 1 2 -48506 +48498 2 @@ -29507,12 +29502,12 @@ 1 2 -6240 +6239 2 3 -943 +942 3 @@ -29533,7 +29528,7 @@ 1 2 -6865 +6864 2 @@ -29554,7 +29549,7 @@ 1 2 -6251 +6250 2 @@ -29574,19 +29569,19 @@ comments -1580291 +1580009 id -1580291 +1580009 contents -784157 +784018 location -1580291 +1580009 @@ -29600,7 +29595,7 @@ 1 2 -1580291 +1580009 @@ -29616,7 +29611,7 @@ 1 2 -1580291 +1580009 @@ -29632,17 +29627,17 @@ 1 2 -663938 +663819 2 3 -75101 +75088 3 10738 -45117 +45109 @@ -29658,17 +29653,17 @@ 1 2 -663938 +663819 2 3 -75101 +75088 3 10738 -45117 +45109 @@ -29684,7 +29679,7 @@ 1 2 -1580291 +1580009 @@ -29700,7 +29695,7 @@ 1 2 -1580291 +1580009 @@ -29710,15 +29705,15 @@ commentbinding -713289 +713206 id -618370 +618260 element -684512 +684434 @@ -29732,17 +29727,17 @@ 1 2 -557010 +556867 2 3 -49044 +49079 3 97 -12315 +12313 @@ -29758,12 +29753,12 @@ 1 2 -655735 +655661 2 3 -28777 +28772 @@ -29826,22 +29821,22 @@ compgenerated -6707729 +6708045 id -6707729 +6708045 synthetic_destructor_call -59594 +59605 element -46379 +46392 i @@ -29849,7 +29844,7 @@ destructor_call -49449 +49463 @@ -29863,12 +29858,12 @@ 1 2 -36936 +36951 2 3 -6766 +6765 3 @@ -29889,12 +29884,12 @@ 1 2 -36936 +36951 2 3 -6766 +6765 3 @@ -29933,8 +29928,8 @@ 21 -4229 -4230 +4231 +4232 10 @@ -29969,8 +29964,8 @@ 21 -3563 -3564 +3565 +3566 10 @@ -29987,17 +29982,17 @@ 1 2 -43604 +43618 2 3 -3619 +3618 3 26 -2226 +2225 @@ -30013,7 +30008,7 @@ 1 2 -49449 +49463 @@ -30023,15 +30018,15 @@ namespaces -7687 +7686 id -7687 +7686 name -4134 +4133 @@ -30045,7 +30040,7 @@ 1 2 -7687 +7686 @@ -30061,7 +30056,7 @@ 1 2 -3476 +3475 2 @@ -30092,15 +30087,15 @@ namespacembrs -1603322 +1603036 parentid -7161 +7160 memberid -1603322 +1603036 @@ -30174,7 +30169,7 @@ 778 39485 -318 +317 @@ -30190,7 +30185,7 @@ 1 2 -1603322 +1603036 @@ -30490,11 +30485,11 @@ iscall -2320176 +2320354 caller -2320176 +2320354 kind @@ -30512,7 +30507,7 @@ 1 2 -2320176 +2320354 @@ -30531,13 +30526,13 @@ 10 -6428 -6429 +6429 +6430 10 -203747 -203748 +203800 +203801 10 @@ -30548,11 +30543,11 @@ numtemplatearguments -164712 +164694 expr_id -164712 +164694 num @@ -30570,7 +30565,7 @@ 1 2 -164712 +164694 @@ -30599,8 +30594,8 @@ 10 -14306 -14307 +14307 +14308 10 @@ -31146,11 +31141,11 @@ expr_allocator -30334 +30329 expr -30334 +30329 func @@ -31172,7 +31167,7 @@ 1 2 -30334 +30329 @@ -31188,7 +31183,7 @@ 1 2 -30334 +30329 @@ -31297,11 +31292,11 @@ expr_deallocator -33306 +33300 expr -33306 +33300 func @@ -31323,7 +31318,7 @@ 1 2 -33306 +33300 @@ -31339,7 +31334,7 @@ 1 2 -33306 +33300 @@ -32525,15 +32520,15 @@ expr_ancestor -66075 +66085 exp -65373 +65384 ancestor -47092 +47105 @@ -32547,12 +32542,12 @@ 1 2 -64737 +64748 2 4 -636 +635 @@ -32568,12 +32563,12 @@ 1 2 -34929 +34945 2 3 -9705 +9704 3 @@ -32600,7 +32595,7 @@ location -3623125 +3622478 @@ -32665,7 +32660,7 @@ 306 -471 +472 87 @@ -32694,18 +32689,18 @@ 87 -6722 +6723 13441 87 17876 -114329 +114359 87 -192875 -428313 +192896 +428379 43 @@ -32798,37 +32793,37 @@ 1 2 -1680540 +1679637 2 3 -738546 +738677 3 4 -319883 +319727 4 5 -276871 +277074 5 9 -301722 +301811 9 53 -272089 +272074 53 144742 -33471 +33476 @@ -32844,17 +32839,17 @@ 1 2 -2587089 +2586627 2 3 -806881 +806737 3 30 -229154 +229113 @@ -32864,15 +32859,15 @@ expr_types -18573253 +18573393 id -18430420 +18430421 typeid -1322513 +1322332 value_category @@ -32890,12 +32885,12 @@ 1 2 -18289045 +18288907 2 4 -141374 +141514 @@ -32911,7 +32906,7 @@ 1 2 -18430420 +18430421 @@ -32927,42 +32922,42 @@ 1 2 -513779 +513731 2 3 -252118 +252041 3 4 -108364 +108355 4 5 -86046 +86009 5 8 -114220 +114200 8 14 -106050 +106042 14 45 -99744 +99759 45 -126302 -42189 +126323 +42193 @@ -32978,17 +32973,17 @@ 1 2 -1170972 +1170807 2 3 -143140 +143125 3 4 -8400 +8399 @@ -33007,13 +33002,13 @@ 10 -370445 -370446 +370541 +370542 10 -1304652 -1304653 +1304856 +1304857 10 @@ -33033,13 +33028,13 @@ 10 -30956 -30957 +30957 +30958 10 -102766 -102767 +102771 +102772 10 @@ -33050,15 +33045,15 @@ new_allocated_type -32133 +32127 expr -32133 +32127 type_id -16516 +16513 @@ -33072,7 +33067,7 @@ 1 2 -32133 +32127 @@ -33088,7 +33083,7 @@ 1 2 -10341 +10339 2 @@ -33713,15 +33708,15 @@ condition_decl_bind -7007 +7028 expr -7007 +7028 decl -7007 +7028 @@ -33735,7 +33730,7 @@ 1 2 -7007 +7028 @@ -33751,7 +33746,7 @@ 1 2 -7007 +7028 @@ -33761,11 +33756,11 @@ typeid_bind -4419 +4418 expr -4419 +4418 type_id @@ -33783,7 +33778,7 @@ 1 2 -4419 +4418 @@ -35478,11 +35473,11 @@ stmts -4688881 +4688614 id -4688881 +4688614 kind @@ -35490,7 +35485,7 @@ location -1194069 +1193856 @@ -35504,7 +35499,7 @@ 1 2 -4688881 +4688614 @@ -35520,7 +35515,7 @@ 1 2 -4688881 +4688614 @@ -35554,8 +35549,8 @@ 10 -735 -736 +736 +737 10 @@ -35569,13 +35564,13 @@ 10 -2235 -2236 +2237 +2238 10 -2266 -2267 +2267 +2268 10 @@ -35584,13 +35579,13 @@ 10 -2826 -2827 +2827 +2828 10 -3119 -3120 +3121 +3122 10 @@ -35599,33 +35594,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 +35743,32 @@ 1 2 -677987 +677438 2 3 -181579 +181952 3 4 -107870 +107851 4 6 -102135 +102116 6 22 -101531 +101535 22 5041 -22964 +22960 @@ -35789,12 +35784,12 @@ 1 2 -1170479 +1170270 2 9 -23589 +23585 @@ -36092,15 +36087,15 @@ while_body -30992 +30997 while_stmt -30992 +30997 body_id -30992 +30997 @@ -36114,7 +36109,7 @@ 1 2 -30992 +30997 @@ -36130,7 +36125,7 @@ 1 2 -30992 +30997 @@ -37427,15 +37422,15 @@ blockscope -1325069 +1324975 block -1325069 +1324975 enclosing -1186907 +1186772 @@ -37449,7 +37444,7 @@ 1 2 -1325069 +1324975 @@ -37465,12 +37460,12 @@ 1 2 -1106552 +1106388 2 509 -80354 +80384 @@ -37666,11 +37661,11 @@ preprocdirects -1323588 +1323352 id -1323588 +1323352 kind @@ -37678,7 +37673,7 @@ location -1317271 +1317036 @@ -37692,7 +37687,7 @@ 1 2 -1323588 +1323352 @@ -37708,7 +37703,7 @@ 1 2 -1323588 +1323352 @@ -37876,12 +37871,12 @@ 1 2 -1316942 +1316707 2 235 -329 +328 @@ -37897,7 +37892,7 @@ 1 2 -1317271 +1317036 @@ -37907,15 +37902,15 @@ preprocpair -378798 +378730 begin -300505 +300451 elseelifend -378798 +378730 @@ -37929,17 +37924,17 @@ 1 2 -238618 +238576 2 3 -54549 +54539 3 53 -7336 +7335 @@ -37955,7 +37950,7 @@ 1 2 -378798 +378730 @@ -37965,41 +37960,41 @@ preproctrue -166565 +166536 branch -166565 +166536 preprocfalse -119122 +119101 branch -119122 +119101 preproctext -965408 +965236 id -965408 +965236 head -463561 +463478 body -175580 +175549 @@ -38013,7 +38008,7 @@ 1 2 -965408 +965236 @@ -38029,7 +38024,7 @@ 1 2 -965408 +965236 @@ -38045,17 +38040,17 @@ 1 2 -345963 +345901 2 3 -78172 +78158 3 19 -34776 +34769 19 @@ -38076,12 +38071,12 @@ 1 2 -441879 +441800 2 38 -21681 +21677 @@ -38097,12 +38092,12 @@ 1 2 -165008 +164979 2 64816 -10572 +10570 @@ -38118,12 +38113,12 @@ 1 2 -166489 +166459 2 21810 -9091 +9089 @@ -38133,15 +38128,15 @@ includes -290843 +290791 id -290843 +290791 included -54604 +54594 @@ -38155,7 +38150,7 @@ 1 2 -290843 +290791 @@ -38171,37 +38166,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 +38254,11 @@ link_parent -18153176 +18149936 element -4992577 +4991686 link_target @@ -38281,32 +38276,32 @@ 1 2 -1493422 +1493156 2 3 -1883187 +1882851 3 4 -718838 +718710 4 6 -400863 +400791 6 29 -398143 +398072 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/ArrayLengthAnalysisTest.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/ArrayLengthAnalysisTest.expected new file mode 100644 index 00000000000..b5e61ed55c5 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/ArrayLengthAnalysisTest.expected @@ -0,0 +1,23 @@ +| test.cpp:15:8:15:11 | Load: aptr | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 0 | +| test.cpp:19:8:19:8 | Load: a | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 | +| test.cpp:21:8:21:8 | Load: a | VNLength(Chi: ptr) | -1 | ZeroOffset | 0 | +| test.cpp:23:8:23:8 | Load: a | VNLength(Chi: ptr) | 1 | ZeroOffset | 0 | +| test.cpp:27:8:27:8 | Load: c | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 | +| test.cpp:28:8:28:24 | Convert: (unsigned char *)... | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 | +| test.cpp:30:8:30:8 | Load: v | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 | +| test.cpp:34:8:34:12 | Convert: array to pointer conversion | ZeroLength | 100 | ZeroOffset | 0 | +| test.cpp:37:10:37:10 | Load: b | VNLength(Chi: ptr) | 0 | ZeroOffset | 0 | +| test.cpp:44:8:44:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 2 | +| test.cpp:53:10:53:10 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 2 | +| test.cpp:56:10:56:10 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 3 | +| test.cpp:63:10:63:14 | CopyValue: & ... | VNLength(InitializeParameter: count) | 0 | OpOffset(Load: i) | 0 | +| test.cpp:66:8:66:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 0 | +| test.cpp:68:8:68:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 3 | +| test.cpp:70:8:70:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 2 | +| test.cpp:72:8:72:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | 0 | +| test.cpp:74:8:74:8 | Load: a | VNLength(InitializeParameter: count) | 0 | ZeroOffset | -10 | +| test.cpp:76:8:76:8 | Load: a | VNLength(InitializeParameter: count) | 1 | ZeroOffset | 0 | +| test.cpp:78:8:78:8 | Load: a | VNLength(InitializeParameter: count) | 1 | OpOffset(Load: count) | 0 | +| test.cpp:80:8:80:8 | Load: a | VNLength(InitializeParameter: count) | 1 | OpOffset(Load: count) | 1 | +| test.cpp:85:8:85:8 | Load: a | VNLength(InitializeParameter: count) | 1 | OpOffset(Add: ... + ...) | 0 | +| test.cpp:87:8:87:8 | Load: a | VNLength(InitializeParameter: count) | 1 | OpOffset(Add: ... + ...) | 1 | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/ArrayLengthAnalysisTest.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/ArrayLengthAnalysisTest.ql new file mode 100644 index 00000000000..020c91cd2d5 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/ArrayLengthAnalysisTest.ql @@ -0,0 +1,8 @@ +import cpp +import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis + +from Instruction array, Length length, int delta, Offset offset, int offsetDelta +where + knownArrayLength(array, length, delta, offset, offsetDelta) and + array.getAUse() instanceof ArgumentOperand +select array, length, delta, offset, offsetDelta diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp new file mode 100644 index 00000000000..b1d9b9a45ba --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp @@ -0,0 +1,95 @@ +void *malloc(unsigned long); +void sink(...); + +typedef struct A { + int a; + int b; + char * c; +} A; + +void test1(unsigned int count) { + if (count < 1) { + return; + } + A* aptr = (A *) malloc(sizeof(A) * count); + sink(aptr); // (count, 0, Zero, 0) + unsigned int* ptr = &count; + sink(ptr); // (Zero, 1, Zero, 0) TODO none, as the feature is not implemented + int* a = (int *) malloc(sizeof(int) * count); + sink(a); // (count, 0, Zero, 0) + a = (int *) malloc(sizeof(int) * (count - 1)); + sink(a); // (count, -1, Zero, 0) + a = (int *) malloc(sizeof(int) * (count + 1)); + sink(a); // (count, 1, Zero, 0) + a = (int *) malloc(sizeof(int) * (2 * count)); + sink(a); // none, as the size expression is too complicated + char* c = (char *)malloc(count); + sink(c); // /count, 0, Zero, 0) + sink((unsigned char*)c); // (count, 0, Zero, 0) + void* v = c; + sink(v); // (count, 0, Zero, 0) + v = malloc(count); + sink((char *)v); // none, as we don't track void* allocations + int stack[100]; + sink(stack); // (Zero, 100, Zero, 0) + for(unsigned int i = 0; i < count; ++i) { + int* b = (int*) malloc(sizeof(int) * count); + sink(b); // (count, 0, Zero, 0) + } +} + +void test2(unsigned int count, bool b) { + int* a = (int *) malloc(sizeof(int) * count); + a = a + 2; + sink(a); // (count, 0, Zero, 2) + for(unsigned int i = 2; i < count; ++i) { + sink(a); // none + a++; + sink(a); // none + } + a = (int*) malloc(sizeof(int) * count); + if (b) { + a += 2; + sink(a); // (count, 0, Zero, 2) + } else { + a += 3; + sink(a); // (count, 0, Zero, 2) + } + sink(a); // none + a -= 2; + sink(a); // none + a = (int*) malloc(sizeof(int) * count); + for(unsigned int i = 0; i < count; i++) { + sink(&a[i]); // (count, 0, i, 0) + } + a = (int*) malloc(sizeof(int) * count); + sink(a); // (count, 0, Zero, 0) + a += 3; + sink(a); // (count, 0, Zero, 3) + a -= 1; + sink(a); // (count, 0, Zero, 2) + a -= 2; + sink(a); // (count, 0, Zero, 0) + a -= 10; + sink(a); // (count, 0, Zero, -10) + a = (int*) malloc(sizeof(int) * (count + 1)); + sink(a); // (count, 1, Zero, 0) + a += count; + sink(a); // (count, 1, count, 0); + a += 1; + sink(a); // (count, 1, count, 1); + a -= count; + sink(a); // none + a = (int*) malloc(sizeof(int) * (count + 1)); + a += count + 1; + sink(a); // TODO, should be (count, 1, count, 1), but is (count, 1, count + 1, 0) + a += 1; + sink(a); // TODO, should be (count, 1, count, 2), but is (count, 1, count + 1, 1) + 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/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.cpp b/cpp/ql/test/library-tests/allocators/allocators.cpp index 92241b9c9e3..3e4a6cec8df 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.cpp +++ b/cpp/ql/test/library-tests/allocators/allocators.cpp @@ -149,3 +149,16 @@ void directOperatorCall() { ptr = operator new(sizeof(int)); operator delete(ptr); } + +void *malloc(size_t); +typedef int* ptr_int; + +void testMalloc(size_t count) { + const volatile int *i = (const volatile int *) malloc(5); + ptr_int i2 = (ptr_int) malloc(5 * sizeof(int)); + volatile long *l = (long *) malloc(count); + l = (long *) malloc(count * sizeof(int)); + const char* c = (const char *) malloc(count * sizeof(int) + 1); + void * v = (void *) malloc(((int) count) * sizeof(void *)); + malloc(sizeof(void *) * sizeof(int)); +} diff --git a/cpp/ql/test/library-tests/allocators/allocators.expected b/cpp/ql/test/library-tests/allocators/allocators.expected index 2f9b4413e8c..5fdf7e50b90 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.expected +++ b/cpp/ql/test/library-tests/allocators/allocators.expected @@ -55,35 +55,43 @@ allocationFunctions | allocators.cpp:122:7:122:20 | operator new[] | getPlacementArgument = 1, getSizeArg = 0 | | allocators.cpp:123:7:123:18 | operator new | getSizeArg = 0, requiresDealloc | | allocators.cpp:124:7:124:20 | operator new[] | getSizeArg = 0, requiresDealloc | +| allocators.cpp:153:7:153:12 | malloc | getSizeArg = 0, requiresDealloc | | file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc | | file://:0:0:0:0 | operator new | getSizeArg = 0, requiresDealloc | | file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc | | file://:0:0:0:0 | operator new[] | getSizeArg = 0, requiresDealloc | allocationExprs -| allocators.cpp:49:3:49:9 | new | getSizeBytes = 4, requiresDealloc | -| allocators.cpp:50:3:50:15 | new | getSizeBytes = 4, requiresDealloc | -| allocators.cpp:51:3:51:11 | new | getSizeBytes = 4, requiresDealloc | -| allocators.cpp:52:3:52:14 | new | getSizeBytes = 8, requiresDealloc | -| allocators.cpp:53:3:53:27 | new | getSizeBytes = 8, requiresDealloc | -| allocators.cpp:54:3:54:17 | new | getSizeBytes = 256, requiresDealloc | -| allocators.cpp:55:3:55:25 | new | getSizeBytes = 256, requiresDealloc | -| allocators.cpp:68:3:68:12 | new[] | getSizeExpr = n, getSizeMult = 4, requiresDealloc | -| allocators.cpp:69:3:69:18 | new[] | getSizeExpr = n, getSizeMult = 4, requiresDealloc | -| allocators.cpp:70:3:70:15 | new[] | getSizeExpr = n, getSizeMult = 8, requiresDealloc | -| allocators.cpp:71:3:71:20 | new[] | getSizeExpr = n, getSizeMult = 256, requiresDealloc | -| allocators.cpp:72:3:72:16 | new[] | getSizeBytes = 80, requiresDealloc | -| allocators.cpp:107:3:107:18 | new | getSizeBytes = 1, requiresDealloc | -| allocators.cpp:108:3:108:19 | new[] | getSizeExpr = n, getSizeMult = 1, requiresDealloc | -| allocators.cpp:109:3:109:35 | new | getSizeBytes = 128, requiresDealloc | -| allocators.cpp:110:3:110:37 | new[] | getSizeBytes = 1280, requiresDealloc | -| allocators.cpp:129:3:129:21 | new | getSizeBytes = 4 | -| allocators.cpp:132:3:132:17 | new[] | getSizeBytes = 4 | -| allocators.cpp:135:3:135:26 | new | getSizeBytes = 4, requiresDealloc | -| allocators.cpp:136:3:136:26 | new[] | getSizeBytes = 8, requiresDealloc | -| allocators.cpp:142:13:142:27 | new[] | getSizeExpr = x, getSizeMult = 10, requiresDealloc | -| allocators.cpp:143:13:143:28 | new[] | getSizeBytes = 400, requiresDealloc | -| allocators.cpp:144:13:144:31 | new[] | getSizeExpr = x, getSizeMult = 900, requiresDealloc | +| allocators.cpp:49:3:49:9 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc | +| allocators.cpp:50:3:50:15 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc | +| allocators.cpp:51:3:51:11 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc | +| allocators.cpp:52:3:52:14 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc | +| allocators.cpp:53:3:53:27 | new | getAllocatedElementType = String, getSizeBytes = 8, requiresDealloc | +| allocators.cpp:54:3:54:17 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc | +| allocators.cpp:55:3:55:25 | new | getAllocatedElementType = Overaligned, getSizeBytes = 256, requiresDealloc | +| allocators.cpp:68:3:68:12 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc | +| allocators.cpp:69:3:69:18 | new[] | getAllocatedElementType = int, getSizeExpr = n, getSizeMult = 4, requiresDealloc | +| allocators.cpp:70:3:70:15 | new[] | getAllocatedElementType = String, getSizeExpr = n, getSizeMult = 8, requiresDealloc | +| allocators.cpp:71:3:71:20 | new[] | getAllocatedElementType = Overaligned, getSizeExpr = n, getSizeMult = 256, requiresDealloc | +| allocators.cpp:72:3:72:16 | new[] | getAllocatedElementType = String, getSizeBytes = 80, requiresDealloc | +| allocators.cpp:107:3:107:18 | new | getAllocatedElementType = FailedInit, getSizeBytes = 1, requiresDealloc | +| allocators.cpp:108:3:108:19 | new[] | getAllocatedElementType = FailedInit, getSizeExpr = n, getSizeMult = 1, requiresDealloc | +| allocators.cpp:109:3:109:35 | new | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 128, requiresDealloc | +| allocators.cpp:110:3:110:37 | new[] | getAllocatedElementType = FailedInitOveraligned, getSizeBytes = 1280, requiresDealloc | +| allocators.cpp:129:3:129:21 | new | getAllocatedElementType = int, getSizeBytes = 4 | +| allocators.cpp:132:3:132:17 | new[] | getAllocatedElementType = int, getSizeBytes = 4 | +| allocators.cpp:135:3:135:26 | new | getAllocatedElementType = int, getSizeBytes = 4, requiresDealloc | +| allocators.cpp:136:3:136:26 | new[] | getAllocatedElementType = int, getSizeBytes = 8, requiresDealloc | +| allocators.cpp:142:13:142:27 | new[] | getAllocatedElementType = char[10], getSizeExpr = x, getSizeMult = 10, requiresDealloc | +| allocators.cpp:143:13:143:28 | new[] | getAllocatedElementType = char[20], getSizeBytes = 400, requiresDealloc | +| allocators.cpp:144:13:144:31 | new[] | getAllocatedElementType = char[30][30], getSizeExpr = x, getSizeMult = 900, requiresDealloc | | allocators.cpp:149:8:149:19 | call to operator new | getSizeBytes = 4, getSizeExpr = sizeof(int), getSizeMult = 1, requiresDealloc | +| allocators.cpp:157:50:157:55 | call to malloc | getAllocatedElementType = const volatile int, getSizeBytes = 5, getSizeExpr = 5, getSizeMult = 1, requiresDealloc | +| allocators.cpp:158:26:158:31 | call to malloc | getAllocatedElementType = int, getSizeBytes = 20, getSizeExpr = 5, getSizeMult = 4, requiresDealloc | +| allocators.cpp:159:31:159:36 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 1, requiresDealloc | +| allocators.cpp:160:16:160:21 | call to malloc | getAllocatedElementType = volatile long, getSizeExpr = count, getSizeMult = 4, requiresDealloc | +| allocators.cpp:161:34:161:39 | call to malloc | getAllocatedElementType = const char, getSizeExpr = ... + ..., getSizeMult = 1, requiresDealloc | +| allocators.cpp:162:23:162:28 | call to malloc | getSizeExpr = count, getSizeMult = 8, requiresDealloc | +| allocators.cpp:163:3:163:8 | call to malloc | getSizeBytes = 32, getSizeExpr = ... * ..., getSizeMult = 1, requiresDealloc | deallocationFunctions | allocators.cpp:11:6:11:20 | operator delete | getFreedArg = 0 | | allocators.cpp:12:6:12:22 | operator delete[] | getFreedArg = 0 | diff --git a/cpp/ql/test/library-tests/allocators/allocators.ql b/cpp/ql/test/library-tests/allocators/allocators.ql index e45667fbf01..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( @@ -138,6 +138,8 @@ string describeAllocationExpr(AllocationExpr e) { or result = "getReallocPtr = " + e.getReallocPtr().toString() or + result = "getAllocatedElementType = " + e.getAllocatedElementType().toString() + or e.requiresDealloc() and result = "requiresDealloc" } diff --git a/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.cpp b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.cpp new file mode 100644 index 00000000000..d9e94faf5f0 --- /dev/null +++ b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.cpp @@ -0,0 +1,9 @@ +struct S1 { + [[deprecated]] int a; + int b; +}; + +struct S2 { + int x; + [[deprecated, gnu::unused]] int b; +}; diff --git a/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.expected b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.expected new file mode 100644 index 00000000000..1a8add6d745 --- /dev/null +++ b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.expected @@ -0,0 +1,3 @@ +| field_attributes.cpp:2:22:2:22 | a | field_attributes.cpp:2:5:2:14 | deprecated | +| field_attributes.cpp:8:35:8:35 | b | field_attributes.cpp:8:5:8:14 | deprecated | +| field_attributes.cpp:8:35:8:35 | b | field_attributes.cpp:8:17:8:27 | unused | diff --git a/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.ql b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.ql new file mode 100644 index 00000000000..e1814bb6b87 --- /dev/null +++ b/cpp/ql/test/library-tests/attributes/field_attributes/field_attributes.ql @@ -0,0 +1,3 @@ +import cpp + +select any(Variable v) as v, v.getAnAttribute() diff --git a/cpp/ql/test/library-tests/attributes/var_attributes/var_attributes.expected b/cpp/ql/test/library-tests/attributes/var_attributes/var_attributes.expected index 2ef69dc6c44..501d699758a 100644 --- a/cpp/ql/test/library-tests/attributes/var_attributes/var_attributes.expected +++ b/cpp/ql/test/library-tests/attributes/var_attributes/var_attributes.expected @@ -3,6 +3,7 @@ | ms_var_attributes.cpp:7:5:7:10 | myInt2 | ms_var_attributes.h:4:1:4:9 | dllexport | | ms_var_attributes.cpp:8:15:8:20 | myInt4 | ms_var_attributes.cpp:8:1:8:9 | dllexport | | ms_var_attributes.cpp:9:5:9:10 | myInt5 | ms_var_attributes.h:7:1:7:9 | dllexport | +| ms_var_attributes.cpp:12:42:12:46 | field | ms_var_attributes.cpp:12:14:12:21 | property | | ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport | | var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak | | var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref | 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/clang_ms/element.expected b/cpp/ql/test/library-tests/clang_ms/element.expected index 16241c2e057..8580209ee9f 100644 --- a/cpp/ql/test/library-tests/clang_ms/element.expected +++ b/cpp/ql/test/library-tests/clang_ms/element.expected @@ -61,6 +61,7 @@ | file://:0:0:0:0 | auto | | file://:0:0:0:0 | bool | | file://:0:0:0:0 | char | +| 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 | const | @@ -90,6 +91,7 @@ | file://:0:0:0:0 | implicit_int | | file://:0:0:0:0 | inline | | file://:0:0:0:0 | int | +| file://:0:0:0:0 | is_consteval | | file://:0:0:0:0 | is_constexpr | | file://:0:0:0:0 | is_thread_local | | file://:0:0:0:0 | long | 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/conditions/elements.expected b/cpp/ql/test/library-tests/conditions/elements.expected index 4e94d425a8a..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 | @@ -38,6 +37,7 @@ | file://:0:0:0:0 | auto | | file://:0:0:0:0 | bool | | file://:0:0:0:0 | char | +| 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 | const | @@ -65,6 +65,7 @@ | file://:0:0:0:0 | initializer for | | file://:0:0:0:0 | inline | | file://:0:0:0:0 | int | +| file://:0:0:0:0 | is_consteval | | file://:0:0:0:0 | is_constexpr | | file://:0:0:0:0 | is_thread_local | | file://:0:0:0:0 | long | @@ -123,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..d01f0daa6a2 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 @@ -2,12 +2,6 @@ uniqueEnclosingCallable uniqueTypeBound uniqueTypeRepr 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 +17,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 7abb7b4f4ae..0bb9343dcaf 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 @@ -19,9 +19,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,6 +28,8 @@ 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 c88a62fc2f1..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,8 +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: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 & ... | @@ -59,8 +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: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 71630f892f5..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 | @@ -31,10 +26,6 @@ | ref.cpp:53:17:53:18 | ref.cpp:62:10:62:11 | AST only | | ref.cpp:53:21:53:22 | ref.cpp:65:10:65:11 | AST only | | ref.cpp:55:23:55:28 | ref.cpp:56:10:56:11 | AST only | -| ref.cpp:94:15:94:20 | ref.cpp:129:13:129:15 | AST only | -| ref.cpp:109:15:109:20 | ref.cpp:132:13:132:15 | AST only | -| ref.cpp:122:23:122:28 | ref.cpp:123:13:123:15 | AST only | -| ref.cpp:125:19:125:24 | ref.cpp:126:13:126:15 | AST only | | test.cpp:75:7:75:8 | test.cpp:76:8:76:9 | AST only | | test.cpp:83:7:83:8 | test.cpp:84:8:84:18 | AST only | | test.cpp:83:7:83:8 | test.cpp:86:8:86:9 | AST only | @@ -43,11 +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:382:48:382:54 | test.cpp:385:8:385:10 | AST only | -| test.cpp:388:53:388:59 | test.cpp:392:8:392:10 | AST only | -| test.cpp:388:53:388:59 | test.cpp:394:10:394:12 | 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 275cbabc075..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,15 @@ | 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 | +| ref.cpp:132:13:132:15 | val | ref.cpp:109:15:109:20 | call to source | | test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source | @@ -61,6 +70,11 @@ | 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 | | test.cpp:450:9:450:22 | (statement expression) | test.cpp:449:26:449:32 | source1 | | test.cpp:461:8:461:12 | local | test.cpp:449:26:449:32 | source1 | | true_upon_entry.cpp:13:8:13:8 | x | true_upon_entry.cpp:9:11:9:16 | call to source | 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..04a03e5fb25 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -4,28 +4,14 @@ uniqueEnclosingCallable 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. | +| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type bound but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [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. | +| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type representation but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type representation but has 0. | 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 +29,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 1714355138c..ba7e3bc0125 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 @@ -2,12 +2,13 @@ uniqueEnclosingCallable uniqueTypeBound uniqueTypeRepr 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 @@ -19,6 +20,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead 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 ca851dc8974..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -1,588 +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_] | -| 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_] | -| 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 | -| 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 new file mode 100644 index 00000000000..d24c311a65b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -0,0 +1,4 @@ +| 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 new file mode 100644 index 00000000000..75ee23e6520 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -0,0 +1,34 @@ +/** + * @kind problem + */ + +import TestUtilities.InlineExpectationsTest +import semmle.code.cpp.ir.dataflow.DataFlow +import IRConfiguration +import cpp + +class IRFieldFlowTest extends InlineExpectationsTest { + IRFieldFlowTest() { this = "IRFieldFlowTest" } + + 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() + ) + } +} 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 6f36fa6551d..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() @@ -53,4 +53,36 @@ void foo() // Nothing should alert bar(i); } + +struct A +{ + int i; +}; + +void single_field_test() +{ + A a; + a.i = user_input(); + A a2 = a; + 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 db34eb16cb8..0fa8c99fde1 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql @@ -1,4 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar from PartialDefinition def -select def, def.getDefinedExpr(), def.getSubBasicBlockStart() +select def.getActualLocation().toString(), "partial def of " + def.toString(), def, + def.getSubBasicBlockStart() 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 ec88e5bc628..e7c66e8a142 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,108 +3,134 @@ | 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 | & ... | | +| 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 | | 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 +174,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 +188,228 @@ | 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 | | +| 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: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:14:40:17 | this | swap1.cpp:43:18:43:22 | this | | +| swap1.cpp:40:26:40:29 | that | swap1.cpp:40:26:40:29 | that | | +| swap1.cpp:40:26:40:29 | that | swap1.cpp:43:25:43:28 | that | | +| swap1.cpp:43:18:43:22 | data1 | swap1.cpp:43:30:43:34 | ref arg data1 | | +| swap1.cpp:43:25:43:28 | that | swap1.cpp:43:18:43:22 | ref arg data1 | | +| swap1.cpp:43:25:43:28 | that [post update] | swap1.cpp:40:26:40:29 | that | | +| swap1.cpp:43:30:43:34 | data1 | swap1.cpp:43:18:43:22 | ref arg data1 | | +| swap1.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | +| swap1.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | +| swap1.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | +| swap1.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | +| swap1.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | +| swap1.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | +| swap1.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | +| swap1.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | +| swap1.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | +| swap1.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | +| swap1.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | +| swap1.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:58:5:58:5 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:60:10:60:10 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:66:10:66:10 | x | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:61:10:61:10 | y | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:63:5:63:5 | y | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:65:10:65:10 | y | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:60:10:60:10 | x | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:66:10:66:10 | x | | +| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:60:12:60:16 | data1 | | +| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:66:12:66:16 | data1 | | +| swap1.cpp:58:15:58:20 | call to source | swap1.cpp:58:5:58:22 | ... = ... | | +| swap1.cpp:63:5:63:5 | ref arg y | swap1.cpp:65:10:65:10 | y | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:69:5:69:6 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:70:10:70:11 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:72:10:72:11 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:72:14:72:15 | z2 | | +| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:74:10:74:11 | z2 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:70:10:70:11 | z1 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:72:10:72:11 | z1 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:70:13:70:17 | data1 | | +| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:75:13:75:17 | data1 | | +| swap1.cpp:69:16:69:21 | call to source | swap1.cpp:69:5:69:23 | ... = ... | | +| swap1.cpp:72:10:72:11 | ref arg z1 | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:72:14:72:15 | ref arg z2 | swap1.cpp:74:10:74:11 | z2 | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:82:5:82:5 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:84:10:84:10 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:87:19:87:19 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:85:10:85:10 | y | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:87:5:87:5 | y | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:89:10:89:10 | y | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:84:10:84:10 | x | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:87:19:87:19 | x | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:84:12:84:16 | data1 | | +| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:90:12:90:16 | data1 | | +| swap1.cpp:82:15:82:20 | call to source | swap1.cpp:82:5:82:22 | ... = ... | | +| swap1.cpp:87:5:87:5 | ref arg y | swap1.cpp:89:10:89:10 | y | | +| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:87:19:87:19 | x [inner post update] | | +| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:9:87:17 | call to move | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:96:5:96:13 | move_from | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:98:10:98:18 | move_from | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:100:41:100:49 | move_from | | +| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:98:10:98:18 | move_from | | +| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:100:41:100:49 | move_from | | +| swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:98:20:98:24 | data1 | | +| swap1.cpp:96:23:96:28 | call to source | swap1.cpp:96:5:96:30 | ... = ... | | +| swap1.cpp:100:31:100:39 | ref arg call to move | swap1.cpp:100:41:100:49 | move_from [inner post update] | | +| swap1.cpp:100:31:100:51 | call to Class | swap1.cpp:102:10:102:16 | move_to | | +| swap1.cpp:100:41:100:49 | move_from | swap1.cpp:100:31:100:39 | 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: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:14:40:17 | this | swap2.cpp:43:18:43:22 | this | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:25:43:28 | that | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:50:43:53 | that | | +| swap2.cpp:43:18:43:22 | data1 | swap2.cpp:43:30:43:34 | ref arg data1 | | +| swap2.cpp:43:18:43:22 | this | swap2.cpp:43:43:43:47 | this | | +| swap2.cpp:43:18:43:22 | this [post update] | swap2.cpp:43:43:43:47 | this | | +| swap2.cpp:43:25:43:28 | that | swap2.cpp:43:18:43:22 | ref arg data1 | | +| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:43:50:43:53 | that | | +| swap2.cpp:43:30:43:34 | data1 | swap2.cpp:43:18:43:22 | ref arg data1 | | +| swap2.cpp:43:43:43:47 | data2 | swap2.cpp:43:55:43:59 | ref arg data2 | | +| swap2.cpp:43:50:43:53 | that | swap2.cpp:43:43:43:47 | ref arg data2 | | +| swap2.cpp:43:50:43:53 | that [post update] | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:43:55:43:59 | data2 | swap2.cpp:43:43:43:47 | ref arg data2 | | +| swap2.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | +| swap2.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | +| swap2.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | +| swap2.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | +| swap2.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | +| swap2.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | +| swap2.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | +| swap2.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | +| swap2.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | +| swap2.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | +| swap2.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | +| swap2.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:58:5:58:5 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:60:10:60:10 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:66:10:66:10 | x | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:61:10:61:10 | y | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:63:5:63:5 | y | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:65:10:65:10 | y | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:60:10:60:10 | x | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:66:10:66:10 | x | | +| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:60:12:60:16 | data1 | | +| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:66:12:66:16 | data1 | | +| swap2.cpp:58:15:58:20 | call to source | swap2.cpp:58:5:58:22 | ... = ... | | +| swap2.cpp:63:5:63:5 | ref arg y | swap2.cpp:65:10:65:10 | y | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:69:5:69:6 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:70:10:70:11 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:72:10:72:11 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:72:14:72:15 | z2 | | +| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:74:10:74:11 | z2 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:70:10:70:11 | z1 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:72:10:72:11 | z1 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:70:13:70:17 | data1 | | +| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:75:13:75:17 | data1 | | +| swap2.cpp:69:16:69:21 | call to source | swap2.cpp:69:5:69:23 | ... = ... | | +| swap2.cpp:72:10:72:11 | ref arg z1 | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:72:14:72:15 | ref arg z2 | swap2.cpp:74:10:74:11 | z2 | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:82:5:82:5 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:84:10:84:10 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:87:19:87:19 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:85:10:85:10 | y | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:87:5:87:5 | y | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:89:10:89:10 | y | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:84:10:84:10 | x | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:87:19:87:19 | x | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:84:12:84:16 | data1 | | +| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:90:12:90:16 | data1 | | +| swap2.cpp:82:15:82:20 | call to source | swap2.cpp:82:5:82:22 | ... = ... | | +| swap2.cpp:87:5:87:5 | ref arg y | swap2.cpp:89:10:89:10 | y | | +| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:87:19:87:19 | x [inner post update] | | +| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:9:87:17 | call to move | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:96:5:96:13 | move_from | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:98:10:98:18 | move_from | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:100:41:100:49 | move_from | | +| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:98:10:98:18 | move_from | | +| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:100:41:100:49 | move_from | | +| swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:98:20:98:24 | data1 | | +| swap2.cpp:96:23:96:28 | call to source | swap2.cpp:96:5:96:30 | ... = ... | | +| swap2.cpp:100:31:100:39 | ref arg call to move | swap2.cpp:100:41:100:49 | move_from [inner post update] | | +| swap2.cpp:100:31:100:51 | call to Class | swap2.cpp:102:10:102:16 | move_to | | +| swap2.cpp:100:41:100:49 | move_from | swap2.cpp:100:31:100:39 | 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 +474,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 | | @@ -299,7 +547,6 @@ | taint.cpp:165:24:165:24 | 0 | taint.cpp:165:22:165:25 | {...} | TAINT | | taint.cpp:168:8:168:14 | ref arg tainted | taint.cpp:172:18:172:24 | tainted | | | taint.cpp:170:10:170:15 | buffer | taint.cpp:170:3:170:8 | call to strcpy | | -| taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:170:3:170:8 | call to strcpy | | | taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:171:8:171:13 | buffer | | | taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:172:10:172:15 | buffer | | | taint.cpp:170:10:170:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | | @@ -309,18 +556,18 @@ | taint.cpp:171:8:171:13 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | | | taint.cpp:172:10:172:15 | buffer | taint.cpp:172:3:172:8 | call to strcat | | | taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT | -| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:172:3:172:8 | call to strcat | | | taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | | | taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT | | 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: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 | @@ -362,7 +609,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 | @@ -480,8 +727,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 | | @@ -526,15 +775,15 @@ | 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 | | @@ -553,22 +802,22 @@ | 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 | | @@ -586,3 +835,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/stl.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp index d92bb39d158..95eeeaf4398 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,28 @@ 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 +} 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..32bfe4c0191 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -0,0 +1,103 @@ +#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; + } + + 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 +} 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..36847a8b5a6 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -0,0 +1,103 @@ +#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; + } + + 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 +} 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..4de3af85f2f 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,53 @@ -| 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 | +| 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 | | 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 | +| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:74:13:74:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:68:27:68:28 | z2 | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:80:23:80:23 | x | +| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:95:23:95:31 | move_from | +| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:74:13:74:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:68:27:68:28 | z2 | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:80:23:80:23 | x | +| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | call to source | +| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:95:23:95:31 | move_from | +| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:96:23:96:28 | 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 +101,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 af9d002dcdc..abe9b42dd46 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,39 +1,43 @@ -| 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 | +| 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 | | 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 | +| swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | +| swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | +| swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | +| swap1.cpp:102:18:102:22 | swap1.cpp:95:23:95:31 | AST only | +| swap2.cpp:74:13:74:17 | swap2.cpp:69:16:69:21 | AST only | +| swap2.cpp:75:13:75:17 | swap2.cpp:68:27:68:28 | AST only | +| swap2.cpp:89:12:89:16 | swap2.cpp:80:23:80:23 | AST only | +| swap2.cpp:102:18:102:22 | swap2.cpp:95:23:95:31 | 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 | +| taint.cpp:112:7:112:13 | taint.cpp:106:12:106:17 | IR only | | 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:216:7:216:7 | taint.cpp:207:6:207:11 | 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 9dc1088434c..4e62d2a6226 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,18 +1,57 @@ +| 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 *)... | +| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | call to source | +| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:96:23:96:28 | 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 | +| taint.cpp:112:7:112:13 | access to array | taint.cpp:106:12:106:17 | call to source | | taint.cpp:129:7:129:9 | * ... | taint.cpp:120:11:120:16 | call to source | | taint.cpp:130:7:130:9 | * ... | taint.cpp:127:8:127:13 | call to source | | taint.cpp:134:7:134:9 | * ... | taint.cpp:120:11:120:16 | call to source | | 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 | @@ -24,3 +63,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 ff7ee26843d..c7a5adde333 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -11,9 +11,12 @@ | 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:48:3:48:4 | f1 | | +| 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:50:3:50:4 | f2 | | +| 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 | | | addressOf.cpp:56:19:56:19 | 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 e218b6daf47..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() @@ -234,6 +234,1487 @@ clang.cpp: # 6| 0: [VariableAccess] globalInt # 6| Type = [IntType] int # 6| ValueCategory = lvalue +complex.c: +# 1| [TopLevelFunction] void complex_literals() +# 1| params: +# 1| body: [Block] { ... } +# 2| 0: [DeclStmt] declaration +# 2| 0: [VariableDeclarationEntry] definition of cf +# 2| Type = [ArithmeticType] _Complex float +# 2| init: [Initializer] initializer for cf +# 2| expr: [CStyleCast] (_Complex float)... +# 2| Conversion = [FloatingPointConversion] floating point conversion +# 2| Type = [ArithmeticType] _Complex float +# 2| ValueCategory = prvalue +# 2| expr: [Literal] 2.0 +# 2| Type = [DoubleType] double +# 2| Value = [Literal] 2.0 +# 2| ValueCategory = prvalue +# 3| 1: [ExprStmt] ExprStmt +# 3| 0: [AssignExpr] ... = ... +# 3| Type = [ArithmeticType] _Complex float +# 3| ValueCategory = prvalue +# 3| 0: [VariableAccess] cf +# 3| Type = [ArithmeticType] _Complex float +# 3| ValueCategory = lvalue +# 3| 1: [CStyleCast] (_Complex float)... +# 3| Conversion = [FloatingPointConversion] floating point conversion +# 3| Type = [ArithmeticType] _Complex float +# 3| ValueCategory = prvalue +# 3| expr: [Literal] 1.0i +# 3| Type = [ArithmeticType] _Imaginary float +# 3| Value = [Literal] 1.0i +# 3| ValueCategory = prvalue +# 4| 2: [DeclStmt] declaration +# 4| 0: [VariableDeclarationEntry] definition of cd +# 4| Type = [ArithmeticType] _Complex double +# 4| init: [Initializer] initializer for cd +# 4| expr: [CStyleCast] (_Complex double)... +# 4| Conversion = [FloatingPointConversion] floating point conversion +# 4| Type = [ArithmeticType] _Complex double +# 4| ValueCategory = prvalue +# 4| expr: [Literal] 3.0 +# 4| Type = [DoubleType] double +# 4| Value = [Literal] 3.0 +# 4| ValueCategory = prvalue +# 5| 3: [ExprStmt] ExprStmt +# 5| 0: [AssignExpr] ... = ... +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = prvalue +# 5| 0: [VariableAccess] cd +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = lvalue +# 5| 1: [CStyleCast] (_Complex double)... +# 5| Conversion = [FloatingPointConversion] floating point conversion +# 5| Type = [ArithmeticType] _Complex double +# 5| ValueCategory = prvalue +# 5| expr: [Literal] 1.0i +# 5| Type = [ArithmeticType] _Imaginary float +# 5| Value = [Literal] 1.0i +# 5| ValueCategory = prvalue +# 6| 4: [DeclStmt] declaration +# 6| 0: [VariableDeclarationEntry] definition of cld +# 6| Type = [ArithmeticType] _Complex long double +# 6| init: [Initializer] initializer for cld +# 6| expr: [CStyleCast] (_Complex long double)... +# 6| Conversion = [FloatingPointConversion] floating point conversion +# 6| Type = [ArithmeticType] _Complex long double +# 6| ValueCategory = prvalue +# 6| expr: [Literal] 5.0 +# 6| Type = [DoubleType] double +# 6| Value = [Literal] 5.0 +# 6| ValueCategory = prvalue +# 7| 5: [ExprStmt] ExprStmt +# 7| 0: [AssignExpr] ... = ... +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = prvalue +# 7| 0: [VariableAccess] cld +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = lvalue +# 7| 1: [CStyleCast] (_Complex long double)... +# 7| Conversion = [FloatingPointConversion] floating point conversion +# 7| Type = [ArithmeticType] _Complex long double +# 7| ValueCategory = prvalue +# 7| expr: [Literal] 1.0i +# 7| Type = [ArithmeticType] _Imaginary float +# 7| Value = [Literal] 1.0i +# 7| ValueCategory = prvalue +# 9| 6: [DeclStmt] declaration +# 9| 0: [VariableDeclarationEntry] definition of jf +# 9| Type = [ArithmeticType] _Imaginary float +# 9| init: [Initializer] initializer for jf +# 9| expr: [Literal] 1.0i +# 9| Type = [ArithmeticType] _Imaginary float +# 9| Value = [Literal] 1.0i +# 9| ValueCategory = prvalue +# 10| 7: [DeclStmt] declaration +# 10| 0: [VariableDeclarationEntry] definition of jd +# 10| Type = [ArithmeticType] _Imaginary double +# 10| init: [Initializer] initializer for jd +# 10| expr: [CStyleCast] (_Imaginary double)... +# 10| Conversion = [FloatingPointConversion] floating point conversion +# 10| Type = [ArithmeticType] _Imaginary double +# 10| ValueCategory = prvalue +# 10| expr: [Literal] 1.0i +# 10| Type = [ArithmeticType] _Imaginary float +# 10| Value = [Literal] 1.0i +# 10| ValueCategory = prvalue +# 11| 8: [DeclStmt] declaration +# 11| 0: [VariableDeclarationEntry] definition of jld +# 11| Type = [ArithmeticType] _Imaginary long double +# 11| init: [Initializer] initializer for jld +# 11| expr: [CStyleCast] (_Imaginary long double)... +# 11| Conversion = [FloatingPointConversion] floating point conversion +# 11| Type = [ArithmeticType] _Imaginary long double +# 11| ValueCategory = prvalue +# 11| expr: [Literal] 1.0i +# 11| Type = [ArithmeticType] _Imaginary float +# 11| Value = [Literal] 1.0i +# 11| ValueCategory = prvalue +# 12| 9: [ReturnStmt] return ... +# 14| [TopLevelFunction] void complex_arithmetic() +# 14| params: +# 14| body: [Block] { ... } +# 15| 0: [DeclStmt] declaration +# 15| 0: [VariableDeclarationEntry] definition of f1 +# 15| Type = [FloatType] float +# 15| init: [Initializer] initializer for f1 +# 15| expr: [CStyleCast] (float)... +# 15| Conversion = [FloatingPointConversion] floating point conversion +# 15| Type = [FloatType] float +# 15| Value = [CStyleCast] 5.0 +# 15| ValueCategory = prvalue +# 15| expr: [Literal] 5.0 +# 15| Type = [DoubleType] double +# 15| Value = [Literal] 5.0 +# 15| ValueCategory = prvalue +# 16| 1: [DeclStmt] declaration +# 16| 0: [VariableDeclarationEntry] definition of f2 +# 16| Type = [FloatType] float +# 16| init: [Initializer] initializer for f2 +# 16| expr: [CStyleCast] (float)... +# 16| Conversion = [FloatingPointConversion] floating point conversion +# 16| Type = [FloatType] float +# 16| Value = [CStyleCast] 7.0 +# 16| ValueCategory = prvalue +# 16| expr: [Literal] 7.0 +# 16| Type = [DoubleType] double +# 16| Value = [Literal] 7.0 +# 16| ValueCategory = prvalue +# 17| 2: [DeclStmt] declaration +# 17| 0: [VariableDeclarationEntry] definition of f3 +# 17| Type = [FloatType] float +# 18| 3: [DeclStmt] declaration +# 18| 0: [VariableDeclarationEntry] definition of cf1 +# 18| Type = [ArithmeticType] _Complex float +# 18| init: [Initializer] initializer for cf1 +# 18| expr: [CStyleCast] (_Complex float)... +# 18| Conversion = [FloatingPointConversion] floating point conversion +# 18| Type = [ArithmeticType] _Complex float +# 18| ValueCategory = prvalue +# 18| expr: [Literal] 2.0 +# 18| Type = [DoubleType] double +# 18| Value = [Literal] 2.0 +# 18| ValueCategory = prvalue +# 19| 4: [DeclStmt] declaration +# 19| 0: [VariableDeclarationEntry] definition of cf2 +# 19| Type = [ArithmeticType] _Complex float +# 19| init: [Initializer] initializer for cf2 +# 19| expr: [CStyleCast] (_Complex float)... +# 19| Conversion = [FloatingPointConversion] floating point conversion +# 19| Type = [ArithmeticType] _Complex float +# 19| ValueCategory = prvalue +# 19| expr: [Literal] 1.0i +# 19| Type = [ArithmeticType] _Imaginary float +# 19| Value = [Literal] 1.0i +# 19| ValueCategory = prvalue +# 20| 5: [DeclStmt] declaration +# 20| 0: [VariableDeclarationEntry] definition of cf3 +# 20| Type = [ArithmeticType] _Complex float +# 21| 6: [DeclStmt] declaration +# 21| 0: [VariableDeclarationEntry] definition of jf1 +# 21| Type = [ArithmeticType] _Imaginary float +# 21| init: [Initializer] initializer for jf1 +# 21| expr: [Literal] 1.0i +# 21| Type = [ArithmeticType] _Imaginary float +# 21| Value = [Literal] 1.0i +# 21| ValueCategory = prvalue +# 22| 7: [DeclStmt] declaration +# 22| 0: [VariableDeclarationEntry] definition of jf2 +# 22| Type = [ArithmeticType] _Imaginary float +# 22| init: [Initializer] initializer for jf2 +# 22| expr: [Literal] 1.0i +# 22| Type = [ArithmeticType] _Imaginary float +# 22| Value = [Literal] 1.0i +# 22| ValueCategory = prvalue +# 23| 8: [DeclStmt] declaration +# 23| 0: [VariableDeclarationEntry] definition of jf3 +# 23| Type = [ArithmeticType] _Imaginary float +# 26| 9: [ExprStmt] ExprStmt +# 26| 0: [AssignExpr] ... = ... +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue +# 26| 0: [VariableAccess] cf3 +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = lvalue +# 26| 1: [UnaryPlusExpr] + ... +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue +# 26| 0: [VariableAccess] cf1 +# 26| Type = [ArithmeticType] _Complex float +# 26| ValueCategory = prvalue(load) +# 27| 10: [ExprStmt] ExprStmt +# 27| 0: [AssignExpr] ... = ... +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue +# 27| 0: [VariableAccess] cf3 +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = lvalue +# 27| 1: [UnaryMinusExpr] - ... +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue +# 27| 0: [VariableAccess] cf1 +# 27| Type = [ArithmeticType] _Complex float +# 27| ValueCategory = prvalue(load) +# 30| 11: [ExprStmt] ExprStmt +# 30| 0: [AssignExpr] ... = ... +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue +# 30| 0: [VariableAccess] cf3 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = lvalue +# 30| 1: [AddExpr] ... + ... +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue +# 30| 0: [VariableAccess] cf1 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue(load) +# 30| 1: [VariableAccess] cf2 +# 30| Type = [ArithmeticType] _Complex float +# 30| ValueCategory = prvalue(load) +# 31| 12: [ExprStmt] ExprStmt +# 31| 0: [AssignExpr] ... = ... +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue +# 31| 0: [VariableAccess] cf3 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = lvalue +# 31| 1: [SubExpr] ... - ... +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue +# 31| 0: [VariableAccess] cf1 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue(load) +# 31| 1: [VariableAccess] cf2 +# 31| Type = [ArithmeticType] _Complex float +# 31| ValueCategory = prvalue(load) +# 32| 13: [ExprStmt] ExprStmt +# 32| 0: [AssignExpr] ... = ... +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue +# 32| 0: [VariableAccess] cf3 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = lvalue +# 32| 1: [MulExpr] ... * ... +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue +# 32| 0: [VariableAccess] cf1 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue(load) +# 32| 1: [VariableAccess] cf2 +# 32| Type = [ArithmeticType] _Complex float +# 32| ValueCategory = prvalue(load) +# 33| 14: [ExprStmt] ExprStmt +# 33| 0: [AssignExpr] ... = ... +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue +# 33| 0: [VariableAccess] cf3 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = lvalue +# 33| 1: [DivExpr] ... / ... +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue +# 33| 0: [VariableAccess] cf1 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue(load) +# 33| 1: [VariableAccess] cf2 +# 33| Type = [ArithmeticType] _Complex float +# 33| ValueCategory = prvalue(load) +# 36| 15: [ExprStmt] ExprStmt +# 36| 0: [AssignExpr] ... = ... +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue +# 36| 0: [VariableAccess] jf3 +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = lvalue +# 36| 1: [UnaryPlusExpr] + ... +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue +# 36| 0: [VariableAccess] jf1 +# 36| Type = [ArithmeticType] _Imaginary float +# 36| ValueCategory = prvalue(load) +# 37| 16: [ExprStmt] ExprStmt +# 37| 0: [AssignExpr] ... = ... +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue +# 37| 0: [VariableAccess] jf3 +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = lvalue +# 37| 1: [UnaryMinusExpr] - ... +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue +# 37| 0: [VariableAccess] jf1 +# 37| Type = [ArithmeticType] _Imaginary float +# 37| ValueCategory = prvalue(load) +# 40| 17: [ExprStmt] ExprStmt +# 40| 0: [AssignExpr] ... = ... +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue +# 40| 0: [VariableAccess] jf3 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = lvalue +# 40| 1: [AddExpr] ... + ... +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue +# 40| 0: [VariableAccess] jf1 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue(load) +# 40| 1: [VariableAccess] jf2 +# 40| Type = [ArithmeticType] _Imaginary float +# 40| ValueCategory = prvalue(load) +# 41| 18: [ExprStmt] ExprStmt +# 41| 0: [AssignExpr] ... = ... +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue +# 41| 0: [VariableAccess] jf3 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = lvalue +# 41| 1: [SubExpr] ... - ... +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue +# 41| 0: [VariableAccess] jf1 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue(load) +# 41| 1: [VariableAccess] jf2 +# 41| Type = [ArithmeticType] _Imaginary float +# 41| ValueCategory = prvalue(load) +# 42| 19: [ExprStmt] ExprStmt +# 42| 0: [AssignExpr] ... = ... +# 42| Type = [FloatType] float +# 42| ValueCategory = prvalue +# 42| 0: [VariableAccess] f3 +# 42| Type = [FloatType] float +# 42| ValueCategory = lvalue +# 42| 1: [ImaginaryMulExpr] ... * ... +# 42| Type = [FloatType] float +# 42| ValueCategory = prvalue +# 42| 0: [VariableAccess] jf1 +# 42| Type = [ArithmeticType] _Imaginary float +# 42| ValueCategory = prvalue(load) +# 42| 1: [VariableAccess] jf2 +# 42| Type = [ArithmeticType] _Imaginary float +# 42| ValueCategory = prvalue(load) +# 43| 20: [ExprStmt] ExprStmt +# 43| 0: [AssignExpr] ... = ... +# 43| Type = [FloatType] float +# 43| ValueCategory = prvalue +# 43| 0: [VariableAccess] f3 +# 43| Type = [FloatType] float +# 43| ValueCategory = lvalue +# 43| 1: [DivExpr] ... / ... +# 43| Type = [FloatType] float +# 43| ValueCategory = prvalue +# 43| 0: [VariableAccess] jf1 +# 43| Type = [ArithmeticType] _Imaginary float +# 43| ValueCategory = prvalue(load) +# 43| 1: [VariableAccess] jf2 +# 43| Type = [ArithmeticType] _Imaginary float +# 43| ValueCategory = prvalue(load) +# 46| 21: [ExprStmt] ExprStmt +# 46| 0: [AssignExpr] ... = ... +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = prvalue +# 46| 0: [VariableAccess] cf3 +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = lvalue +# 46| 1: [ImaginaryRealAddExpr] ... + ... +# 46| Type = [ArithmeticType] _Complex float +# 46| ValueCategory = prvalue +# 46| 0: [VariableAccess] jf1 +# 46| Type = [ArithmeticType] _Imaginary float +# 46| ValueCategory = prvalue(load) +# 46| 1: [VariableAccess] f2 +# 46| Type = [FloatType] float +# 46| ValueCategory = prvalue(load) +# 47| 22: [ExprStmt] ExprStmt +# 47| 0: [AssignExpr] ... = ... +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = prvalue +# 47| 0: [VariableAccess] cf3 +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = lvalue +# 47| 1: [ImaginaryRealSubExpr] ... - ... +# 47| Type = [ArithmeticType] _Complex float +# 47| ValueCategory = prvalue +# 47| 0: [VariableAccess] jf1 +# 47| Type = [ArithmeticType] _Imaginary float +# 47| ValueCategory = prvalue(load) +# 47| 1: [VariableAccess] f2 +# 47| Type = [FloatType] float +# 47| ValueCategory = prvalue(load) +# 48| 23: [ExprStmt] ExprStmt +# 48| 0: [AssignExpr] ... = ... +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue +# 48| 0: [VariableAccess] jf3 +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = lvalue +# 48| 1: [MulExpr] ... * ... +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue +# 48| 0: [VariableAccess] jf1 +# 48| Type = [ArithmeticType] _Imaginary float +# 48| ValueCategory = prvalue(load) +# 48| 1: [VariableAccess] f2 +# 48| Type = [FloatType] float +# 48| ValueCategory = prvalue(load) +# 49| 24: [ExprStmt] ExprStmt +# 49| 0: [AssignExpr] ... = ... +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue +# 49| 0: [VariableAccess] jf3 +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = lvalue +# 49| 1: [DivExpr] ... / ... +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue +# 49| 0: [VariableAccess] jf1 +# 49| Type = [ArithmeticType] _Imaginary float +# 49| ValueCategory = prvalue(load) +# 49| 1: [VariableAccess] f2 +# 49| Type = [FloatType] float +# 49| ValueCategory = prvalue(load) +# 52| 25: [ExprStmt] ExprStmt +# 52| 0: [AssignExpr] ... = ... +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = prvalue +# 52| 0: [VariableAccess] cf3 +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = lvalue +# 52| 1: [RealImaginaryAddExpr] ... + ... +# 52| Type = [ArithmeticType] _Complex float +# 52| ValueCategory = prvalue +# 52| 0: [VariableAccess] f1 +# 52| Type = [FloatType] float +# 52| ValueCategory = prvalue(load) +# 52| 1: [VariableAccess] jf2 +# 52| Type = [ArithmeticType] _Imaginary float +# 52| ValueCategory = prvalue(load) +# 53| 26: [ExprStmt] ExprStmt +# 53| 0: [AssignExpr] ... = ... +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = prvalue +# 53| 0: [VariableAccess] cf3 +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = lvalue +# 53| 1: [RealImaginarySubExpr] ... - ... +# 53| Type = [ArithmeticType] _Complex float +# 53| ValueCategory = prvalue +# 53| 0: [VariableAccess] f1 +# 53| Type = [FloatType] float +# 53| ValueCategory = prvalue(load) +# 53| 1: [VariableAccess] jf2 +# 53| Type = [ArithmeticType] _Imaginary float +# 53| ValueCategory = prvalue(load) +# 54| 27: [ExprStmt] ExprStmt +# 54| 0: [AssignExpr] ... = ... +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue +# 54| 0: [VariableAccess] jf3 +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = lvalue +# 54| 1: [MulExpr] ... * ... +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue +# 54| 0: [VariableAccess] f1 +# 54| Type = [FloatType] float +# 54| ValueCategory = prvalue(load) +# 54| 1: [VariableAccess] jf2 +# 54| Type = [ArithmeticType] _Imaginary float +# 54| ValueCategory = prvalue(load) +# 55| 28: [ExprStmt] ExprStmt +# 55| 0: [AssignExpr] ... = ... +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue +# 55| 0: [VariableAccess] jf3 +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = lvalue +# 55| 1: [ImaginaryDivExpr] ... / ... +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue +# 55| 0: [VariableAccess] f1 +# 55| Type = [FloatType] float +# 55| ValueCategory = prvalue(load) +# 55| 1: [VariableAccess] jf2 +# 55| Type = [ArithmeticType] _Imaginary float +# 55| ValueCategory = prvalue(load) +# 56| 29: [ReturnStmt] return ... +# 58| [TopLevelFunction] void complex_conversions() +# 58| params: +# 58| body: [Block] { ... } +# 59| 0: [DeclStmt] declaration +# 59| 0: [VariableDeclarationEntry] definition of f +# 59| Type = [FloatType] float +# 59| init: [Initializer] initializer for f +# 59| expr: [CStyleCast] (float)... +# 59| Conversion = [FloatingPointConversion] floating point conversion +# 59| Type = [FloatType] float +# 59| Value = [CStyleCast] 2.0 +# 59| ValueCategory = prvalue +# 59| expr: [Literal] 2.0 +# 59| Type = [DoubleType] double +# 59| Value = [Literal] 2.0 +# 59| ValueCategory = prvalue +# 60| 1: [DeclStmt] declaration +# 60| 0: [VariableDeclarationEntry] definition of d +# 60| Type = [DoubleType] double +# 60| init: [Initializer] initializer for d +# 60| expr: [Literal] 3.0 +# 60| Type = [DoubleType] double +# 60| Value = [Literal] 3.0 +# 60| ValueCategory = prvalue +# 61| 2: [DeclStmt] declaration +# 61| 0: [VariableDeclarationEntry] definition of ld +# 61| Type = [LongDoubleType] long double +# 61| init: [Initializer] initializer for ld +# 61| expr: [CStyleCast] (long double)... +# 61| Conversion = [FloatingPointConversion] floating point conversion +# 61| Type = [LongDoubleType] long double +# 61| Value = [CStyleCast] 5.0 +# 61| ValueCategory = prvalue +# 61| expr: [Literal] 5.0 +# 61| Type = [DoubleType] double +# 61| Value = [Literal] 5.0 +# 61| ValueCategory = prvalue +# 62| 3: [DeclStmt] declaration +# 62| 0: [VariableDeclarationEntry] definition of cf +# 62| Type = [ArithmeticType] _Complex float +# 62| init: [Initializer] initializer for cf +# 62| expr: [CStyleCast] (_Complex float)... +# 62| Conversion = [FloatingPointConversion] floating point conversion +# 62| Type = [ArithmeticType] _Complex float +# 62| ValueCategory = prvalue +# 62| expr: [Literal] 7.0 +# 62| Type = [DoubleType] double +# 62| Value = [Literal] 7.0 +# 62| ValueCategory = prvalue +# 63| 4: [DeclStmt] declaration +# 63| 0: [VariableDeclarationEntry] definition of cd +# 63| Type = [ArithmeticType] _Complex double +# 63| init: [Initializer] initializer for cd +# 63| expr: [CStyleCast] (_Complex double)... +# 63| Conversion = [FloatingPointConversion] floating point conversion +# 63| Type = [ArithmeticType] _Complex double +# 63| ValueCategory = prvalue +# 63| expr: [Literal] 11.0 +# 63| Type = [DoubleType] double +# 63| Value = [Literal] 11.0 +# 63| ValueCategory = prvalue +# 64| 5: [DeclStmt] declaration +# 64| 0: [VariableDeclarationEntry] definition of cld +# 64| Type = [ArithmeticType] _Complex long double +# 64| init: [Initializer] initializer for cld +# 64| expr: [CStyleCast] (_Complex long double)... +# 64| Conversion = [FloatingPointConversion] floating point conversion +# 64| Type = [ArithmeticType] _Complex long double +# 64| ValueCategory = prvalue +# 64| expr: [Literal] 13.0 +# 64| Type = [DoubleType] double +# 64| Value = [Literal] 13.0 +# 64| ValueCategory = prvalue +# 65| 6: [DeclStmt] declaration +# 65| 0: [VariableDeclarationEntry] definition of jf +# 65| Type = [ArithmeticType] _Imaginary float +# 65| init: [Initializer] initializer for jf +# 65| expr: [Literal] 1.0i +# 65| Type = [ArithmeticType] _Imaginary float +# 65| Value = [Literal] 1.0i +# 65| ValueCategory = prvalue +# 66| 7: [DeclStmt] declaration +# 66| 0: [VariableDeclarationEntry] definition of jd +# 66| Type = [ArithmeticType] _Imaginary double +# 66| init: [Initializer] initializer for jd +# 66| expr: [CStyleCast] (_Imaginary double)... +# 66| Conversion = [FloatingPointConversion] floating point conversion +# 66| Type = [ArithmeticType] _Imaginary double +# 66| ValueCategory = prvalue +# 66| expr: [Literal] 1.0i +# 66| Type = [ArithmeticType] _Imaginary float +# 66| Value = [Literal] 1.0i +# 66| ValueCategory = prvalue +# 67| 8: [DeclStmt] declaration +# 67| 0: [VariableDeclarationEntry] definition of jld +# 67| Type = [ArithmeticType] _Imaginary long double +# 67| init: [Initializer] initializer for jld +# 67| expr: [CStyleCast] (_Imaginary long double)... +# 67| Conversion = [FloatingPointConversion] floating point conversion +# 67| Type = [ArithmeticType] _Imaginary long double +# 67| ValueCategory = prvalue +# 67| expr: [Literal] 1.0i +# 67| Type = [ArithmeticType] _Imaginary float +# 67| Value = [Literal] 1.0i +# 67| ValueCategory = prvalue +# 70| 9: [ExprStmt] ExprStmt +# 70| 0: [AssignExpr] ... = ... +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = prvalue +# 70| 0: [VariableAccess] cf +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = lvalue +# 70| 1: [VariableAccess] cf +# 70| Type = [ArithmeticType] _Complex float +# 70| ValueCategory = prvalue(load) +# 71| 10: [ExprStmt] ExprStmt +# 71| 0: [AssignExpr] ... = ... +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = prvalue +# 71| 0: [VariableAccess] cf +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = lvalue +# 71| 1: [CStyleCast] (_Complex float)... +# 71| Conversion = [FloatingPointConversion] floating point conversion +# 71| Type = [ArithmeticType] _Complex float +# 71| ValueCategory = prvalue +# 71| expr: [VariableAccess] cd +# 71| Type = [ArithmeticType] _Complex double +# 71| ValueCategory = prvalue(load) +# 72| 11: [ExprStmt] ExprStmt +# 72| 0: [AssignExpr] ... = ... +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = prvalue +# 72| 0: [VariableAccess] cf +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = lvalue +# 72| 1: [CStyleCast] (_Complex float)... +# 72| Conversion = [FloatingPointConversion] floating point conversion +# 72| Type = [ArithmeticType] _Complex float +# 72| ValueCategory = prvalue +# 72| expr: [VariableAccess] cld +# 72| Type = [ArithmeticType] _Complex long double +# 72| ValueCategory = prvalue(load) +# 73| 12: [ExprStmt] ExprStmt +# 73| 0: [AssignExpr] ... = ... +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = prvalue +# 73| 0: [VariableAccess] cd +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = lvalue +# 73| 1: [CStyleCast] (_Complex double)... +# 73| Conversion = [FloatingPointConversion] floating point conversion +# 73| Type = [ArithmeticType] _Complex double +# 73| ValueCategory = prvalue +# 73| expr: [VariableAccess] cf +# 73| Type = [ArithmeticType] _Complex float +# 73| ValueCategory = prvalue(load) +# 74| 13: [ExprStmt] ExprStmt +# 74| 0: [AssignExpr] ... = ... +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = prvalue +# 74| 0: [VariableAccess] cd +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = lvalue +# 74| 1: [VariableAccess] cd +# 74| Type = [ArithmeticType] _Complex double +# 74| ValueCategory = prvalue(load) +# 75| 14: [ExprStmt] ExprStmt +# 75| 0: [AssignExpr] ... = ... +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = prvalue +# 75| 0: [VariableAccess] cd +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = lvalue +# 75| 1: [CStyleCast] (_Complex double)... +# 75| Conversion = [FloatingPointConversion] floating point conversion +# 75| Type = [ArithmeticType] _Complex double +# 75| ValueCategory = prvalue +# 75| expr: [VariableAccess] cld +# 75| Type = [ArithmeticType] _Complex long double +# 75| ValueCategory = prvalue(load) +# 76| 15: [ExprStmt] ExprStmt +# 76| 0: [AssignExpr] ... = ... +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = prvalue +# 76| 0: [VariableAccess] cld +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = lvalue +# 76| 1: [CStyleCast] (_Complex long double)... +# 76| Conversion = [FloatingPointConversion] floating point conversion +# 76| Type = [ArithmeticType] _Complex long double +# 76| ValueCategory = prvalue +# 76| expr: [VariableAccess] cf +# 76| Type = [ArithmeticType] _Complex float +# 76| ValueCategory = prvalue(load) +# 77| 16: [ExprStmt] ExprStmt +# 77| 0: [AssignExpr] ... = ... +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = prvalue +# 77| 0: [VariableAccess] cld +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = lvalue +# 77| 1: [CStyleCast] (_Complex long double)... +# 77| Conversion = [FloatingPointConversion] floating point conversion +# 77| Type = [ArithmeticType] _Complex long double +# 77| ValueCategory = prvalue +# 77| expr: [VariableAccess] cd +# 77| Type = [ArithmeticType] _Complex double +# 77| ValueCategory = prvalue(load) +# 78| 17: [ExprStmt] ExprStmt +# 78| 0: [AssignExpr] ... = ... +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = prvalue +# 78| 0: [VariableAccess] cld +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = lvalue +# 78| 1: [VariableAccess] cld +# 78| Type = [ArithmeticType] _Complex long double +# 78| ValueCategory = prvalue(load) +# 81| 18: [ExprStmt] ExprStmt +# 81| 0: [AssignExpr] ... = ... +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = prvalue +# 81| 0: [VariableAccess] cf +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = lvalue +# 81| 1: [CStyleCast] (_Complex float)... +# 81| Conversion = [FloatingPointConversion] floating point conversion +# 81| Type = [ArithmeticType] _Complex float +# 81| ValueCategory = prvalue +# 81| expr: [VariableAccess] f +# 81| Type = [FloatType] float +# 81| ValueCategory = prvalue(load) +# 82| 19: [ExprStmt] ExprStmt +# 82| 0: [AssignExpr] ... = ... +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = prvalue +# 82| 0: [VariableAccess] cf +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = lvalue +# 82| 1: [CStyleCast] (_Complex float)... +# 82| Conversion = [FloatingPointConversion] floating point conversion +# 82| Type = [ArithmeticType] _Complex float +# 82| ValueCategory = prvalue +# 82| expr: [VariableAccess] d +# 82| Type = [DoubleType] double +# 82| ValueCategory = prvalue(load) +# 83| 20: [ExprStmt] ExprStmt +# 83| 0: [AssignExpr] ... = ... +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = prvalue +# 83| 0: [VariableAccess] cf +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = lvalue +# 83| 1: [CStyleCast] (_Complex float)... +# 83| Conversion = [FloatingPointConversion] floating point conversion +# 83| Type = [ArithmeticType] _Complex float +# 83| ValueCategory = prvalue +# 83| expr: [VariableAccess] ld +# 83| Type = [LongDoubleType] long double +# 83| ValueCategory = prvalue(load) +# 84| 21: [ExprStmt] ExprStmt +# 84| 0: [AssignExpr] ... = ... +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = prvalue +# 84| 0: [VariableAccess] cd +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = lvalue +# 84| 1: [CStyleCast] (_Complex double)... +# 84| Conversion = [FloatingPointConversion] floating point conversion +# 84| Type = [ArithmeticType] _Complex double +# 84| ValueCategory = prvalue +# 84| expr: [VariableAccess] f +# 84| Type = [FloatType] float +# 84| ValueCategory = prvalue(load) +# 85| 22: [ExprStmt] ExprStmt +# 85| 0: [AssignExpr] ... = ... +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = prvalue +# 85| 0: [VariableAccess] cd +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = lvalue +# 85| 1: [CStyleCast] (_Complex double)... +# 85| Conversion = [FloatingPointConversion] floating point conversion +# 85| Type = [ArithmeticType] _Complex double +# 85| ValueCategory = prvalue +# 85| expr: [VariableAccess] d +# 85| Type = [DoubleType] double +# 85| ValueCategory = prvalue(load) +# 86| 23: [ExprStmt] ExprStmt +# 86| 0: [AssignExpr] ... = ... +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = prvalue +# 86| 0: [VariableAccess] cd +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = lvalue +# 86| 1: [CStyleCast] (_Complex double)... +# 86| Conversion = [FloatingPointConversion] floating point conversion +# 86| Type = [ArithmeticType] _Complex double +# 86| ValueCategory = prvalue +# 86| expr: [VariableAccess] ld +# 86| Type = [LongDoubleType] long double +# 86| ValueCategory = prvalue(load) +# 87| 24: [ExprStmt] ExprStmt +# 87| 0: [AssignExpr] ... = ... +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = prvalue +# 87| 0: [VariableAccess] cld +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = lvalue +# 87| 1: [CStyleCast] (_Complex long double)... +# 87| Conversion = [FloatingPointConversion] floating point conversion +# 87| Type = [ArithmeticType] _Complex long double +# 87| ValueCategory = prvalue +# 87| expr: [VariableAccess] f +# 87| Type = [FloatType] float +# 87| ValueCategory = prvalue(load) +# 88| 25: [ExprStmt] ExprStmt +# 88| 0: [AssignExpr] ... = ... +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = prvalue +# 88| 0: [VariableAccess] cld +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = lvalue +# 88| 1: [CStyleCast] (_Complex long double)... +# 88| Conversion = [FloatingPointConversion] floating point conversion +# 88| Type = [ArithmeticType] _Complex long double +# 88| ValueCategory = prvalue +# 88| expr: [VariableAccess] d +# 88| Type = [DoubleType] double +# 88| ValueCategory = prvalue(load) +# 89| 26: [ExprStmt] ExprStmt +# 89| 0: [AssignExpr] ... = ... +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = prvalue +# 89| 0: [VariableAccess] cld +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = lvalue +# 89| 1: [CStyleCast] (_Complex long double)... +# 89| Conversion = [FloatingPointConversion] floating point conversion +# 89| Type = [ArithmeticType] _Complex long double +# 89| ValueCategory = prvalue +# 89| expr: [VariableAccess] ld +# 89| Type = [LongDoubleType] long double +# 89| ValueCategory = prvalue(load) +# 92| 27: [ExprStmt] ExprStmt +# 92| 0: [AssignExpr] ... = ... +# 92| Type = [FloatType] float +# 92| ValueCategory = prvalue +# 92| 0: [VariableAccess] f +# 92| Type = [FloatType] float +# 92| ValueCategory = lvalue +# 92| 1: [CStyleCast] (float)... +# 92| Conversion = [FloatingPointConversion] floating point conversion +# 92| Type = [FloatType] float +# 92| ValueCategory = prvalue +# 92| expr: [VariableAccess] cf +# 92| Type = [ArithmeticType] _Complex float +# 92| ValueCategory = prvalue(load) +# 93| 28: [ExprStmt] ExprStmt +# 93| 0: [AssignExpr] ... = ... +# 93| Type = [FloatType] float +# 93| ValueCategory = prvalue +# 93| 0: [VariableAccess] f +# 93| Type = [FloatType] float +# 93| ValueCategory = lvalue +# 93| 1: [CStyleCast] (float)... +# 93| Conversion = [FloatingPointConversion] floating point conversion +# 93| Type = [FloatType] float +# 93| ValueCategory = prvalue +# 93| expr: [VariableAccess] cd +# 93| Type = [ArithmeticType] _Complex double +# 93| ValueCategory = prvalue(load) +# 94| 29: [ExprStmt] ExprStmt +# 94| 0: [AssignExpr] ... = ... +# 94| Type = [FloatType] float +# 94| ValueCategory = prvalue +# 94| 0: [VariableAccess] f +# 94| Type = [FloatType] float +# 94| ValueCategory = lvalue +# 94| 1: [CStyleCast] (float)... +# 94| Conversion = [FloatingPointConversion] floating point conversion +# 94| Type = [FloatType] float +# 94| ValueCategory = prvalue +# 94| expr: [VariableAccess] cld +# 94| Type = [ArithmeticType] _Complex long double +# 94| ValueCategory = prvalue(load) +# 95| 30: [ExprStmt] ExprStmt +# 95| 0: [AssignExpr] ... = ... +# 95| Type = [DoubleType] double +# 95| ValueCategory = prvalue +# 95| 0: [VariableAccess] d +# 95| Type = [DoubleType] double +# 95| ValueCategory = lvalue +# 95| 1: [CStyleCast] (double)... +# 95| Conversion = [FloatingPointConversion] floating point conversion +# 95| Type = [DoubleType] double +# 95| ValueCategory = prvalue +# 95| expr: [VariableAccess] cf +# 95| Type = [ArithmeticType] _Complex float +# 95| ValueCategory = prvalue(load) +# 96| 31: [ExprStmt] ExprStmt +# 96| 0: [AssignExpr] ... = ... +# 96| Type = [DoubleType] double +# 96| ValueCategory = prvalue +# 96| 0: [VariableAccess] d +# 96| Type = [DoubleType] double +# 96| ValueCategory = lvalue +# 96| 1: [CStyleCast] (double)... +# 96| Conversion = [FloatingPointConversion] floating point conversion +# 96| Type = [DoubleType] double +# 96| ValueCategory = prvalue +# 96| expr: [VariableAccess] cd +# 96| Type = [ArithmeticType] _Complex double +# 96| ValueCategory = prvalue(load) +# 97| 32: [ExprStmt] ExprStmt +# 97| 0: [AssignExpr] ... = ... +# 97| Type = [DoubleType] double +# 97| ValueCategory = prvalue +# 97| 0: [VariableAccess] d +# 97| Type = [DoubleType] double +# 97| ValueCategory = lvalue +# 97| 1: [CStyleCast] (double)... +# 97| Conversion = [FloatingPointConversion] floating point conversion +# 97| Type = [DoubleType] double +# 97| ValueCategory = prvalue +# 97| expr: [VariableAccess] cld +# 97| Type = [ArithmeticType] _Complex long double +# 97| ValueCategory = prvalue(load) +# 98| 33: [ExprStmt] ExprStmt +# 98| 0: [AssignExpr] ... = ... +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = prvalue +# 98| 0: [VariableAccess] ld +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = lvalue +# 98| 1: [CStyleCast] (long double)... +# 98| Conversion = [FloatingPointConversion] floating point conversion +# 98| Type = [LongDoubleType] long double +# 98| ValueCategory = prvalue +# 98| expr: [VariableAccess] cf +# 98| Type = [ArithmeticType] _Complex float +# 98| ValueCategory = prvalue(load) +# 99| 34: [ExprStmt] ExprStmt +# 99| 0: [AssignExpr] ... = ... +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = prvalue +# 99| 0: [VariableAccess] ld +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = lvalue +# 99| 1: [CStyleCast] (long double)... +# 99| Conversion = [FloatingPointConversion] floating point conversion +# 99| Type = [LongDoubleType] long double +# 99| ValueCategory = prvalue +# 99| expr: [VariableAccess] cd +# 99| Type = [ArithmeticType] _Complex double +# 99| ValueCategory = prvalue(load) +# 100| 35: [ExprStmt] ExprStmt +# 100| 0: [AssignExpr] ... = ... +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = prvalue +# 100| 0: [VariableAccess] ld +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = lvalue +# 100| 1: [CStyleCast] (long double)... +# 100| Conversion = [FloatingPointConversion] floating point conversion +# 100| Type = [LongDoubleType] long double +# 100| ValueCategory = prvalue +# 100| expr: [VariableAccess] cld +# 100| Type = [ArithmeticType] _Complex long double +# 100| ValueCategory = prvalue(load) +# 103| 36: [ExprStmt] ExprStmt +# 103| 0: [AssignExpr] ... = ... +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = prvalue +# 103| 0: [VariableAccess] cf +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = lvalue +# 103| 1: [CStyleCast] (_Complex float)... +# 103| Conversion = [FloatingPointConversion] floating point conversion +# 103| Type = [ArithmeticType] _Complex float +# 103| ValueCategory = prvalue +# 103| expr: [VariableAccess] jf +# 103| Type = [ArithmeticType] _Imaginary float +# 103| ValueCategory = prvalue(load) +# 104| 37: [ExprStmt] ExprStmt +# 104| 0: [AssignExpr] ... = ... +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = prvalue +# 104| 0: [VariableAccess] cf +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = lvalue +# 104| 1: [CStyleCast] (_Complex float)... +# 104| Conversion = [FloatingPointConversion] floating point conversion +# 104| Type = [ArithmeticType] _Complex float +# 104| ValueCategory = prvalue +# 104| expr: [VariableAccess] jd +# 104| Type = [ArithmeticType] _Imaginary double +# 104| ValueCategory = prvalue(load) +# 105| 38: [ExprStmt] ExprStmt +# 105| 0: [AssignExpr] ... = ... +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = prvalue +# 105| 0: [VariableAccess] cf +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = lvalue +# 105| 1: [CStyleCast] (_Complex float)... +# 105| Conversion = [FloatingPointConversion] floating point conversion +# 105| Type = [ArithmeticType] _Complex float +# 105| ValueCategory = prvalue +# 105| expr: [VariableAccess] jld +# 105| Type = [ArithmeticType] _Imaginary long double +# 105| ValueCategory = prvalue(load) +# 106| 39: [ExprStmt] ExprStmt +# 106| 0: [AssignExpr] ... = ... +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = prvalue +# 106| 0: [VariableAccess] cd +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = lvalue +# 106| 1: [CStyleCast] (_Complex double)... +# 106| Conversion = [FloatingPointConversion] floating point conversion +# 106| Type = [ArithmeticType] _Complex double +# 106| ValueCategory = prvalue +# 106| expr: [VariableAccess] jf +# 106| Type = [ArithmeticType] _Imaginary float +# 106| ValueCategory = prvalue(load) +# 107| 40: [ExprStmt] ExprStmt +# 107| 0: [AssignExpr] ... = ... +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = prvalue +# 107| 0: [VariableAccess] cd +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = lvalue +# 107| 1: [CStyleCast] (_Complex double)... +# 107| Conversion = [FloatingPointConversion] floating point conversion +# 107| Type = [ArithmeticType] _Complex double +# 107| ValueCategory = prvalue +# 107| expr: [VariableAccess] jd +# 107| Type = [ArithmeticType] _Imaginary double +# 107| ValueCategory = prvalue(load) +# 108| 41: [ExprStmt] ExprStmt +# 108| 0: [AssignExpr] ... = ... +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = prvalue +# 108| 0: [VariableAccess] cd +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = lvalue +# 108| 1: [CStyleCast] (_Complex double)... +# 108| Conversion = [FloatingPointConversion] floating point conversion +# 108| Type = [ArithmeticType] _Complex double +# 108| ValueCategory = prvalue +# 108| expr: [VariableAccess] jld +# 108| Type = [ArithmeticType] _Imaginary long double +# 108| ValueCategory = prvalue(load) +# 109| 42: [ExprStmt] ExprStmt +# 109| 0: [AssignExpr] ... = ... +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = prvalue +# 109| 0: [VariableAccess] cld +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = lvalue +# 109| 1: [CStyleCast] (_Complex long double)... +# 109| Conversion = [FloatingPointConversion] floating point conversion +# 109| Type = [ArithmeticType] _Complex long double +# 109| ValueCategory = prvalue +# 109| expr: [VariableAccess] jf +# 109| Type = [ArithmeticType] _Imaginary float +# 109| ValueCategory = prvalue(load) +# 110| 43: [ExprStmt] ExprStmt +# 110| 0: [AssignExpr] ... = ... +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = prvalue +# 110| 0: [VariableAccess] cld +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = lvalue +# 110| 1: [CStyleCast] (_Complex long double)... +# 110| Conversion = [FloatingPointConversion] floating point conversion +# 110| Type = [ArithmeticType] _Complex long double +# 110| ValueCategory = prvalue +# 110| expr: [VariableAccess] jd +# 110| Type = [ArithmeticType] _Imaginary double +# 110| ValueCategory = prvalue(load) +# 111| 44: [ExprStmt] ExprStmt +# 111| 0: [AssignExpr] ... = ... +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = prvalue +# 111| 0: [VariableAccess] cld +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = lvalue +# 111| 1: [CStyleCast] (_Complex long double)... +# 111| Conversion = [FloatingPointConversion] floating point conversion +# 111| Type = [ArithmeticType] _Complex long double +# 111| ValueCategory = prvalue +# 111| expr: [VariableAccess] jld +# 111| Type = [ArithmeticType] _Imaginary long double +# 111| ValueCategory = prvalue(load) +# 114| 45: [ExprStmt] ExprStmt +# 114| 0: [AssignExpr] ... = ... +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = prvalue +# 114| 0: [VariableAccess] jf +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = lvalue +# 114| 1: [CStyleCast] (_Imaginary float)... +# 114| Conversion = [FloatingPointConversion] floating point conversion +# 114| Type = [ArithmeticType] _Imaginary float +# 114| ValueCategory = prvalue +# 114| expr: [VariableAccess] cf +# 114| Type = [ArithmeticType] _Complex float +# 114| ValueCategory = prvalue(load) +# 115| 46: [ExprStmt] ExprStmt +# 115| 0: [AssignExpr] ... = ... +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = prvalue +# 115| 0: [VariableAccess] jf +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = lvalue +# 115| 1: [CStyleCast] (_Imaginary float)... +# 115| Conversion = [FloatingPointConversion] floating point conversion +# 115| Type = [ArithmeticType] _Imaginary float +# 115| ValueCategory = prvalue +# 115| expr: [VariableAccess] cd +# 115| Type = [ArithmeticType] _Complex double +# 115| ValueCategory = prvalue(load) +# 116| 47: [ExprStmt] ExprStmt +# 116| 0: [AssignExpr] ... = ... +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = prvalue +# 116| 0: [VariableAccess] jf +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = lvalue +# 116| 1: [CStyleCast] (_Imaginary float)... +# 116| Conversion = [FloatingPointConversion] floating point conversion +# 116| Type = [ArithmeticType] _Imaginary float +# 116| ValueCategory = prvalue +# 116| expr: [VariableAccess] cld +# 116| Type = [ArithmeticType] _Complex long double +# 116| ValueCategory = prvalue(load) +# 117| 48: [ExprStmt] ExprStmt +# 117| 0: [AssignExpr] ... = ... +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = prvalue +# 117| 0: [VariableAccess] jd +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = lvalue +# 117| 1: [CStyleCast] (_Imaginary double)... +# 117| Conversion = [FloatingPointConversion] floating point conversion +# 117| Type = [ArithmeticType] _Imaginary double +# 117| ValueCategory = prvalue +# 117| expr: [VariableAccess] cf +# 117| Type = [ArithmeticType] _Complex float +# 117| ValueCategory = prvalue(load) +# 118| 49: [ExprStmt] ExprStmt +# 118| 0: [AssignExpr] ... = ... +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = prvalue +# 118| 0: [VariableAccess] jd +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = lvalue +# 118| 1: [CStyleCast] (_Imaginary double)... +# 118| Conversion = [FloatingPointConversion] floating point conversion +# 118| Type = [ArithmeticType] _Imaginary double +# 118| ValueCategory = prvalue +# 118| expr: [VariableAccess] cd +# 118| Type = [ArithmeticType] _Complex double +# 118| ValueCategory = prvalue(load) +# 119| 50: [ExprStmt] ExprStmt +# 119| 0: [AssignExpr] ... = ... +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = prvalue +# 119| 0: [VariableAccess] jd +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = lvalue +# 119| 1: [CStyleCast] (_Imaginary double)... +# 119| Conversion = [FloatingPointConversion] floating point conversion +# 119| Type = [ArithmeticType] _Imaginary double +# 119| ValueCategory = prvalue +# 119| expr: [VariableAccess] cld +# 119| Type = [ArithmeticType] _Complex long double +# 119| ValueCategory = prvalue(load) +# 120| 51: [ExprStmt] ExprStmt +# 120| 0: [AssignExpr] ... = ... +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = prvalue +# 120| 0: [VariableAccess] jld +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = lvalue +# 120| 1: [CStyleCast] (_Imaginary long double)... +# 120| Conversion = [FloatingPointConversion] floating point conversion +# 120| Type = [ArithmeticType] _Imaginary long double +# 120| ValueCategory = prvalue +# 120| expr: [VariableAccess] cf +# 120| Type = [ArithmeticType] _Complex float +# 120| ValueCategory = prvalue(load) +# 121| 52: [ExprStmt] ExprStmt +# 121| 0: [AssignExpr] ... = ... +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = prvalue +# 121| 0: [VariableAccess] jld +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = lvalue +# 121| 1: [CStyleCast] (_Imaginary long double)... +# 121| Conversion = [FloatingPointConversion] floating point conversion +# 121| Type = [ArithmeticType] _Imaginary long double +# 121| ValueCategory = prvalue +# 121| expr: [VariableAccess] cd +# 121| Type = [ArithmeticType] _Complex double +# 121| ValueCategory = prvalue(load) +# 122| 53: [ExprStmt] ExprStmt +# 122| 0: [AssignExpr] ... = ... +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = prvalue +# 122| 0: [VariableAccess] jld +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = lvalue +# 122| 1: [CStyleCast] (_Imaginary long double)... +# 122| Conversion = [FloatingPointConversion] floating point conversion +# 122| Type = [ArithmeticType] _Imaginary long double +# 122| ValueCategory = prvalue +# 122| expr: [VariableAccess] cld +# 122| Type = [ArithmeticType] _Complex long double +# 122| ValueCategory = prvalue(load) +# 125| 54: [ExprStmt] ExprStmt +# 125| 0: [AssignExpr] ... = ... +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = prvalue +# 125| 0: [VariableAccess] jf +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = lvalue +# 125| 1: [CStyleCast] (_Imaginary float)... +# 125| Conversion = [FloatingPointConversion] floating point conversion +# 125| Type = [ArithmeticType] _Imaginary float +# 125| ValueCategory = prvalue +# 125| expr: [VariableAccess] f +# 125| Type = [FloatType] float +# 125| ValueCategory = prvalue(load) +# 126| 55: [ExprStmt] ExprStmt +# 126| 0: [AssignExpr] ... = ... +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = prvalue +# 126| 0: [VariableAccess] jf +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = lvalue +# 126| 1: [CStyleCast] (_Imaginary float)... +# 126| Conversion = [FloatingPointConversion] floating point conversion +# 126| Type = [ArithmeticType] _Imaginary float +# 126| ValueCategory = prvalue +# 126| expr: [VariableAccess] d +# 126| Type = [DoubleType] double +# 126| ValueCategory = prvalue(load) +# 127| 56: [ExprStmt] ExprStmt +# 127| 0: [AssignExpr] ... = ... +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = prvalue +# 127| 0: [VariableAccess] jf +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = lvalue +# 127| 1: [CStyleCast] (_Imaginary float)... +# 127| Conversion = [FloatingPointConversion] floating point conversion +# 127| Type = [ArithmeticType] _Imaginary float +# 127| ValueCategory = prvalue +# 127| expr: [VariableAccess] ld +# 127| Type = [LongDoubleType] long double +# 127| ValueCategory = prvalue(load) +# 128| 57: [ExprStmt] ExprStmt +# 128| 0: [AssignExpr] ... = ... +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = prvalue +# 128| 0: [VariableAccess] jd +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = lvalue +# 128| 1: [CStyleCast] (_Imaginary double)... +# 128| Conversion = [FloatingPointConversion] floating point conversion +# 128| Type = [ArithmeticType] _Imaginary double +# 128| ValueCategory = prvalue +# 128| expr: [VariableAccess] f +# 128| Type = [FloatType] float +# 128| ValueCategory = prvalue(load) +# 129| 58: [ExprStmt] ExprStmt +# 129| 0: [AssignExpr] ... = ... +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = prvalue +# 129| 0: [VariableAccess] jd +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = lvalue +# 129| 1: [CStyleCast] (_Imaginary double)... +# 129| Conversion = [FloatingPointConversion] floating point conversion +# 129| Type = [ArithmeticType] _Imaginary double +# 129| ValueCategory = prvalue +# 129| expr: [VariableAccess] d +# 129| Type = [DoubleType] double +# 129| ValueCategory = prvalue(load) +# 130| 59: [ExprStmt] ExprStmt +# 130| 0: [AssignExpr] ... = ... +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = prvalue +# 130| 0: [VariableAccess] jd +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = lvalue +# 130| 1: [CStyleCast] (_Imaginary double)... +# 130| Conversion = [FloatingPointConversion] floating point conversion +# 130| Type = [ArithmeticType] _Imaginary double +# 130| ValueCategory = prvalue +# 130| expr: [VariableAccess] ld +# 130| Type = [LongDoubleType] long double +# 130| ValueCategory = prvalue(load) +# 131| 60: [ExprStmt] ExprStmt +# 131| 0: [AssignExpr] ... = ... +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = prvalue +# 131| 0: [VariableAccess] jld +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = lvalue +# 131| 1: [CStyleCast] (_Imaginary long double)... +# 131| Conversion = [FloatingPointConversion] floating point conversion +# 131| Type = [ArithmeticType] _Imaginary long double +# 131| ValueCategory = prvalue +# 131| expr: [VariableAccess] f +# 131| Type = [FloatType] float +# 131| ValueCategory = prvalue(load) +# 132| 61: [ExprStmt] ExprStmt +# 132| 0: [AssignExpr] ... = ... +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = prvalue +# 132| 0: [VariableAccess] jld +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = lvalue +# 132| 1: [CStyleCast] (_Imaginary long double)... +# 132| Conversion = [FloatingPointConversion] floating point conversion +# 132| Type = [ArithmeticType] _Imaginary long double +# 132| ValueCategory = prvalue +# 132| expr: [VariableAccess] d +# 132| Type = [DoubleType] double +# 132| ValueCategory = prvalue(load) +# 133| 62: [ExprStmt] ExprStmt +# 133| 0: [AssignExpr] ... = ... +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = prvalue +# 133| 0: [VariableAccess] jld +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = lvalue +# 133| 1: [CStyleCast] (_Imaginary long double)... +# 133| Conversion = [FloatingPointConversion] floating point conversion +# 133| Type = [ArithmeticType] _Imaginary long double +# 133| ValueCategory = prvalue +# 133| expr: [VariableAccess] ld +# 133| Type = [LongDoubleType] long double +# 133| ValueCategory = prvalue(load) +# 136| 63: [ExprStmt] ExprStmt +# 136| 0: [AssignExpr] ... = ... +# 136| Type = [FloatType] float +# 136| ValueCategory = prvalue +# 136| 0: [VariableAccess] f +# 136| Type = [FloatType] float +# 136| ValueCategory = lvalue +# 136| 1: [CStyleCast] (float)... +# 136| Conversion = [FloatingPointConversion] floating point conversion +# 136| Type = [FloatType] float +# 136| ValueCategory = prvalue +# 136| expr: [VariableAccess] jf +# 136| Type = [ArithmeticType] _Imaginary float +# 136| ValueCategory = prvalue(load) +# 137| 64: [ExprStmt] ExprStmt +# 137| 0: [AssignExpr] ... = ... +# 137| Type = [FloatType] float +# 137| ValueCategory = prvalue +# 137| 0: [VariableAccess] f +# 137| Type = [FloatType] float +# 137| ValueCategory = lvalue +# 137| 1: [CStyleCast] (float)... +# 137| Conversion = [FloatingPointConversion] floating point conversion +# 137| Type = [FloatType] float +# 137| ValueCategory = prvalue +# 137| expr: [VariableAccess] jd +# 137| Type = [ArithmeticType] _Imaginary double +# 137| ValueCategory = prvalue(load) +# 138| 65: [ExprStmt] ExprStmt +# 138| 0: [AssignExpr] ... = ... +# 138| Type = [FloatType] float +# 138| ValueCategory = prvalue +# 138| 0: [VariableAccess] f +# 138| Type = [FloatType] float +# 138| ValueCategory = lvalue +# 138| 1: [CStyleCast] (float)... +# 138| Conversion = [FloatingPointConversion] floating point conversion +# 138| Type = [FloatType] float +# 138| ValueCategory = prvalue +# 138| expr: [VariableAccess] jld +# 138| Type = [ArithmeticType] _Imaginary long double +# 138| ValueCategory = prvalue(load) +# 139| 66: [ExprStmt] ExprStmt +# 139| 0: [AssignExpr] ... = ... +# 139| Type = [DoubleType] double +# 139| ValueCategory = prvalue +# 139| 0: [VariableAccess] d +# 139| Type = [DoubleType] double +# 139| ValueCategory = lvalue +# 139| 1: [CStyleCast] (double)... +# 139| Conversion = [FloatingPointConversion] floating point conversion +# 139| Type = [DoubleType] double +# 139| ValueCategory = prvalue +# 139| expr: [VariableAccess] jf +# 139| Type = [ArithmeticType] _Imaginary float +# 139| ValueCategory = prvalue(load) +# 140| 67: [ExprStmt] ExprStmt +# 140| 0: [AssignExpr] ... = ... +# 140| Type = [DoubleType] double +# 140| ValueCategory = prvalue +# 140| 0: [VariableAccess] d +# 140| Type = [DoubleType] double +# 140| ValueCategory = lvalue +# 140| 1: [CStyleCast] (double)... +# 140| Conversion = [FloatingPointConversion] floating point conversion +# 140| Type = [DoubleType] double +# 140| ValueCategory = prvalue +# 140| expr: [VariableAccess] jd +# 140| Type = [ArithmeticType] _Imaginary double +# 140| ValueCategory = prvalue(load) +# 141| 68: [ExprStmt] ExprStmt +# 141| 0: [AssignExpr] ... = ... +# 141| Type = [DoubleType] double +# 141| ValueCategory = prvalue +# 141| 0: [VariableAccess] d +# 141| Type = [DoubleType] double +# 141| ValueCategory = lvalue +# 141| 1: [CStyleCast] (double)... +# 141| Conversion = [FloatingPointConversion] floating point conversion +# 141| Type = [DoubleType] double +# 141| ValueCategory = prvalue +# 141| expr: [VariableAccess] jld +# 141| Type = [ArithmeticType] _Imaginary long double +# 141| ValueCategory = prvalue(load) +# 142| 69: [ExprStmt] ExprStmt +# 142| 0: [AssignExpr] ... = ... +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = prvalue +# 142| 0: [VariableAccess] ld +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = lvalue +# 142| 1: [CStyleCast] (long double)... +# 142| Conversion = [FloatingPointConversion] floating point conversion +# 142| Type = [LongDoubleType] long double +# 142| ValueCategory = prvalue +# 142| expr: [VariableAccess] jf +# 142| Type = [ArithmeticType] _Imaginary float +# 142| ValueCategory = prvalue(load) +# 143| 70: [ExprStmt] ExprStmt +# 143| 0: [AssignExpr] ... = ... +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = prvalue +# 143| 0: [VariableAccess] ld +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = lvalue +# 143| 1: [CStyleCast] (long double)... +# 143| Conversion = [FloatingPointConversion] floating point conversion +# 143| Type = [LongDoubleType] long double +# 143| ValueCategory = prvalue +# 143| expr: [VariableAccess] jd +# 143| Type = [ArithmeticType] _Imaginary double +# 143| ValueCategory = prvalue(load) +# 144| 71: [ExprStmt] ExprStmt +# 144| 0: [AssignExpr] ... = ... +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = prvalue +# 144| 0: [VariableAccess] ld +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = lvalue +# 144| 1: [CStyleCast] (long double)... +# 144| Conversion = [FloatingPointConversion] floating point conversion +# 144| Type = [LongDoubleType] long double +# 144| ValueCategory = prvalue +# 144| expr: [VariableAccess] jld +# 144| Type = [ArithmeticType] _Imaginary long double +# 144| ValueCategory = prvalue(load) +# 145| 72: [ReturnStmt] return ... ir.cpp: # 1| [TopLevelFunction] void Constants() # 1| params: @@ -4140,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 @@ -4192,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: @@ -4231,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 @@ -4692,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 & @@ -4777,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 @@ -4806,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 & @@ -4888,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 @@ -4917,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 & @@ -7052,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 @@ -7091,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 @@ -7166,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 @@ -7368,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 @@ -7423,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 @@ -7464,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 @@ -7514,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 @@ -7553,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 @@ -7594,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 @@ -7694,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 (...) ... @@ -7735,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 (...) ... @@ -8054,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 @@ -8750,6 +10231,287 @@ ir.cpp: # 1286| Type = [PointerType] A * # 1286| ValueCategory = prvalue # 1287| 12: [ReturnStmt] return ... +# 1289| [TopLevelFunction] int missingReturnValue(bool, int) +# 1289| params: +# 1289| 0: [Parameter] b +# 1289| Type = [BoolType] bool +# 1289| 1: [Parameter] x +# 1289| Type = [IntType] int +# 1289| body: [Block] { ... } +# 1290| 0: [IfStmt] if (...) ... +# 1290| 0: [VariableAccess] b +# 1290| Type = [BoolType] bool +# 1290| ValueCategory = prvalue(load) +# 1290| 1: [Block] { ... } +# 1291| 0: [ReturnStmt] return ... +# 1291| 0: [VariableAccess] x +# 1291| Type = [IntType] int +# 1291| ValueCategory = prvalue(load) +# 1293| 1: [ReturnStmt] return ... +# 1295| [TopLevelFunction] void returnVoid(int, int) +# 1295| params: +# 1295| 0: [Parameter] x +# 1295| Type = [IntType] int +# 1295| 1: [Parameter] y +# 1295| Type = [IntType] int +# 1295| body: [Block] { ... } +# 1296| 0: [ReturnStmt] return ... +# 1296| 0: [FunctionCall] call to IntegerOps +# 1296| Type = [VoidType] void +# 1296| ValueCategory = prvalue +# 1296| 0: [VariableAccess] x +# 1296| Type = [IntType] int +# 1296| ValueCategory = prvalue(load) +# 1296| 1: [VariableAccess] y +# 1296| Type = [IntType] int +# 1296| ValueCategory = prvalue(load) +# 1299| [TopLevelFunction] void gccBinaryConditional(bool, int, long) +# 1299| params: +# 1299| 0: [Parameter] b +# 1299| Type = [BoolType] bool +# 1299| 1: [Parameter] x +# 1299| Type = [IntType] int +# 1299| 2: [Parameter] y +# 1299| Type = [LongType] long +# 1299| body: [Block] { ... } +# 1300| 0: [DeclStmt] declaration +# 1300| 0: [VariableDeclarationEntry] definition of z +# 1300| Type = [IntType] int +# 1300| init: [Initializer] initializer for z +# 1300| expr: [VariableAccess] x +# 1300| Type = [IntType] int +# 1300| ValueCategory = prvalue(load) +# 1301| 1: [ExprStmt] ExprStmt +# 1301| 0: [AssignExpr] ... = ... +# 1301| Type = [IntType] int +# 1301| ValueCategory = lvalue +# 1301| 0: [VariableAccess] z +# 1301| Type = [IntType] int +# 1301| ValueCategory = lvalue +# 1301| 1: [ConditionalExpr] ... ? ... : ... +# 1301| Type = [IntType] int +# 1301| ValueCategory = prvalue +# 1301| 0: [VariableAccess] b +# 1301| Type = [BoolType] bool +# 1301| ValueCategory = prvalue(load) +# 1301| 1: [VariableAccess] x +# 1301| Type = [IntType] int +# 1301| ValueCategory = prvalue(load) +# 1302| 2: [ExprStmt] ExprStmt +# 1302| 0: [AssignExpr] ... = ... +# 1302| Type = [IntType] int +# 1302| ValueCategory = lvalue +# 1302| 0: [VariableAccess] z +# 1302| Type = [IntType] int +# 1302| ValueCategory = lvalue +# 1302| 1: [CStyleCast] (int)... +# 1302| Conversion = [IntegralConversion] integral conversion +# 1302| Type = [IntType] int +# 1302| ValueCategory = prvalue +# 1302| expr: [ConditionalExpr] ... ? ... : ... +# 1302| Type = [LongType] long +# 1302| ValueCategory = prvalue +# 1302| 0: [VariableAccess] b +# 1302| Type = [BoolType] bool +# 1302| ValueCategory = prvalue(load) +# 1302| 1: [VariableAccess] y +# 1302| Type = [LongType] long +# 1302| ValueCategory = prvalue(load) +# 1303| 3: [ExprStmt] ExprStmt +# 1303| 0: [AssignExpr] ... = ... +# 1303| Type = [IntType] int +# 1303| ValueCategory = lvalue +# 1303| 0: [VariableAccess] z +# 1303| Type = [IntType] int +# 1303| ValueCategory = lvalue +# 1303| 1: [ConditionalExpr] ... ? ... : ... +# 1303| Type = [IntType] int +# 1303| ValueCategory = prvalue +# 1303| 0: [CStyleCast] (bool)... +# 1303| Conversion = [BoolConversion] conversion to bool +# 1303| Type = [BoolType] bool +# 1303| ValueCategory = prvalue +# 1303| expr: [VariableAccess] x +# 1303| Type = [IntType] int +# 1303| ValueCategory = prvalue(load) +# 1303| 1: [VariableAccess] x +# 1303| Type = [IntType] int +# 1303| ValueCategory = prvalue(load) +# 1304| 4: [ExprStmt] ExprStmt +# 1304| 0: [AssignExpr] ... = ... +# 1304| Type = [IntType] int +# 1304| ValueCategory = lvalue +# 1304| 0: [VariableAccess] z +# 1304| Type = [IntType] int +# 1304| ValueCategory = lvalue +# 1304| 1: [CStyleCast] (int)... +# 1304| Conversion = [IntegralConversion] integral conversion +# 1304| Type = [IntType] int +# 1304| ValueCategory = prvalue +# 1304| expr: [ConditionalExpr] ... ? ... : ... +# 1304| Type = [LongType] long +# 1304| ValueCategory = prvalue +# 1304| 0: [CStyleCast] (bool)... +# 1304| Conversion = [BoolConversion] conversion to bool +# 1304| Type = [BoolType] bool +# 1304| ValueCategory = prvalue +# 1304| expr: [VariableAccess] x +# 1304| Type = [IntType] int +# 1304| ValueCategory = prvalue(load) +# 1304| 1: [VariableAccess] y +# 1304| Type = [LongType] long +# 1304| ValueCategory = prvalue(load) +# 1305| 5: [ExprStmt] ExprStmt +# 1305| 0: [AssignExpr] ... = ... +# 1305| Type = [IntType] int +# 1305| ValueCategory = lvalue +# 1305| 0: [VariableAccess] z +# 1305| Type = [IntType] int +# 1305| ValueCategory = lvalue +# 1305| 1: [CStyleCast] (int)... +# 1305| Conversion = [IntegralConversion] integral conversion +# 1305| Type = [IntType] int +# 1305| ValueCategory = prvalue +# 1305| expr: [ConditionalExpr] ... ? ... : ... +# 1305| Type = [LongType] long +# 1305| ValueCategory = prvalue +# 1305| 0: [CStyleCast] (bool)... +# 1305| Conversion = [BoolConversion] conversion to bool +# 1305| Type = [BoolType] bool +# 1305| ValueCategory = prvalue +# 1305| expr: [VariableAccess] y +# 1305| Type = [LongType] long +# 1305| ValueCategory = prvalue(load) +# 1305| 1: [CStyleCast] (long)... +# 1305| Conversion = [IntegralConversion] integral conversion +# 1305| Type = [LongType] long +# 1305| ValueCategory = prvalue +# 1305| expr: [VariableAccess] x +# 1305| Type = [IntType] int +# 1305| ValueCategory = prvalue(load) +# 1306| 6: [ExprStmt] ExprStmt +# 1306| 0: [AssignExpr] ... = ... +# 1306| Type = [IntType] int +# 1306| ValueCategory = lvalue +# 1306| 0: [VariableAccess] z +# 1306| Type = [IntType] int +# 1306| ValueCategory = lvalue +# 1306| 1: [CStyleCast] (int)... +# 1306| Conversion = [IntegralConversion] integral conversion +# 1306| Type = [IntType] int +# 1306| ValueCategory = prvalue +# 1306| expr: [ConditionalExpr] ... ? ... : ... +# 1306| Type = [LongType] long +# 1306| ValueCategory = prvalue +# 1306| 0: [CStyleCast] (bool)... +# 1306| Conversion = [BoolConversion] conversion to bool +# 1306| Type = [BoolType] bool +# 1306| ValueCategory = prvalue +# 1306| expr: [VariableAccess] y +# 1306| Type = [LongType] long +# 1306| ValueCategory = prvalue(load) +# 1306| 1: [VariableAccess] y +# 1306| Type = [LongType] long +# 1306| ValueCategory = prvalue(load) +# 1308| 7: [ExprStmt] ExprStmt +# 1308| 0: [AssignExpr] ... = ... +# 1308| Type = [IntType] int +# 1308| ValueCategory = lvalue +# 1308| 0: [VariableAccess] z +# 1308| Type = [IntType] int +# 1308| ValueCategory = lvalue +# 1308| 1: [ConditionalExpr] ... ? ... : ... +# 1308| Type = [IntType] int +# 1308| ValueCategory = prvalue +# 1308| 0: [ParenthesisExpr] (...) +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue +# 1308| expr: [LogicalOrExpr] ... || ... +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue +# 1308| 0: [LogicalAndExpr] ... && ... +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue +# 1308| 0: [CStyleCast] (bool)... +# 1308| Conversion = [BoolConversion] conversion to bool +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue +# 1308| expr: [VariableAccess] x +# 1308| Type = [IntType] int +# 1308| ValueCategory = prvalue(load) +# 1308| 1: [VariableAccess] b +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue(load) +# 1308| 1: [CStyleCast] (bool)... +# 1308| Conversion = [BoolConversion] conversion to bool +# 1308| Type = [BoolType] bool +# 1308| ValueCategory = prvalue +# 1308| expr: [VariableAccess] y +# 1308| Type = [LongType] long +# 1308| ValueCategory = prvalue(load) +# 1308| 1: [VariableAccess] x +# 1308| Type = [IntType] int +# 1308| ValueCategory = prvalue(load) +# 1309| 8: [ReturnStmt] return ... +# 1311| [TopLevelFunction] bool predicateA() +# 1311| params: +# 1312| [TopLevelFunction] bool predicateB() +# 1312| params: +# 1314| [TopLevelFunction] int shortCircuitConditional(int, int) +# 1314| params: +# 1314| 0: [Parameter] x +# 1314| Type = [IntType] int +# 1314| 1: [Parameter] y +# 1314| Type = [IntType] int +# 1314| body: [Block] { ... } +# 1315| 0: [ReturnStmt] return ... +# 1315| 0: [ConditionalExpr] ... ? ... : ... +# 1315| Type = [IntType] int +# 1315| ValueCategory = prvalue +# 1315| 0: [LogicalAndExpr] ... && ... +# 1315| Type = [BoolType] bool +# 1315| ValueCategory = prvalue +# 1315| 0: [FunctionCall] call to predicateA +# 1315| Type = [BoolType] bool +# 1315| ValueCategory = prvalue +# 1315| 1: [FunctionCall] call to predicateB +# 1315| Type = [BoolType] bool +# 1315| ValueCategory = prvalue +# 1315| 1: [VariableAccess] x +# 1315| Type = [IntType] int +# 1315| ValueCategory = prvalue(load) +# 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 79% 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 735555b5a4b..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 @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -23,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 79% 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 735555b5a4b..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 @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -23,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/complex.c b/cpp/ql/test/library-tests/ir/ir/complex.c new file mode 100644 index 00000000000..d2009778ae5 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/complex.c @@ -0,0 +1,147 @@ +void complex_literals(void) { + _Complex float cf = 2.0; + cf = __I__; + _Complex double cd = 3.0; + cd = __I__; + _Complex long double cld = 5.0; + cld = __I__; + + _Imaginary float jf = __I__; + _Imaginary double jd = __I__; + _Imaginary long double jld = __I__; +} + +void complex_arithmetic(void) { + float f1 = 5.0; + float f2 = 7.0; + float f3; + _Complex float cf1 = 2.0; + _Complex float cf2 = __I__; + _Complex float cf3; + _Imaginary float jf1 = __I__; + _Imaginary float jf2 = __I__; + _Imaginary float jf3; + + // unaryop _Complex + cf3 = +cf1; + cf3 = -cf1; + + // _Complex binaryop _Complex + cf3 = cf1 + cf2; + cf3 = cf1 - cf2; + cf3 = cf1 * cf2; + cf3 = cf1 / cf2; + + // unaryop _Imaginary + jf3 = +jf1; + jf3 = -jf1; + + // _Imaginary binaryop _Imaginary + jf3 = jf1 + jf2; + jf3 = jf1 - jf2; + f3 = jf1 * jf2; // Result is _Real + f3 = jf1 / jf2; // Result is _Real + + // _Imaginary binaryop _Real + cf3 = jf1 + f2; + cf3 = jf1 - f2; + jf3 = jf1 * f2; // Result is _Imaginary + jf3 = jf1 / f2; // Result is _Imaginary + + // _Real binaryop _Imaginary + cf3 = f1 + jf2; + cf3 = f1 - jf2; + jf3 = f1 * jf2; // Result is _Imaginary + jf3 = f1 / jf2; // Result is _Imaginary +} + +void complex_conversions(void) { + float f = 2.0; + double d = 3.0; + long double ld = 5.0; + _Complex float cf = 7.0; + _Complex double cd = 11.0; + _Complex long double cld = 13.0; + _Imaginary float jf = __I__; + _Imaginary double jd = __I__; + _Imaginary long double jld = __I__; + + // _Complex to _Complex + cf = cf; + cf = cd; + cf = cld; + cd = cf; + cd = cd; + cd = cld; + cld = cf; + cld = cd; + cld = cld; + + // _Real to _Complex + cf = f; + cf = d; + cf = ld; + cd = f; + cd = d; + cd = ld; + cld = f; + cld = d; + cld = ld; + + // _Complex to _Real + f = cf; + f = cd; + f = cld; + d = cf; + d = cd; + d = cld; + ld = cf; + ld = cd; + ld = cld; + + // _Imaginary to _Complex + cf = jf; + cf = jd; + cf = jld; + cd = jf; + cd = jd; + cd = jld; + cld = jf; + cld = jd; + cld = jld; + + // _Complex to _Imaginary + jf = cf; + jf = cd; + jf = cld; + jd = cf; + jd = cd; + jd = cld; + jld = cf; + jld = cd; + jld = cld; + + // _Real to _Imaginary + jf = f; + jf = d; + jf = ld; + jd = f; + jd = d; + jd = ld; + jld = f; + jld = d; + jld = ld; + + // _Imaginary to _Real + f = jf; + f = jd; + f = jld; + d = jf; + d = jd; + d = jld; + ld = jf; + ld = jd; + ld = jld; +} + +// semmle-extractor-options: --microsoft --edg --c99 diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index ec40d944789..54b198d9537 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1249,10 +1249,10 @@ char *strcpy(char *destination, const char *source); char *strcat(char *destination, const char *source); void test_strings(char *s1, char *s2) { - char buffer[1024] = {0}; + char buffer[1024] = {0}; - strcpy(buffer, s1); - strcat(buffer, s2); + strcpy(buffer, s1); + strcat(buffer, s2); } struct A { @@ -1286,4 +1286,40 @@ void test_static_member_functions(int int_arg, A* a_arg) { getAnInstanceOfA()->static_member_without_def(); } +int missingReturnValue(bool b, int x) { + if (b) { + return x; + } +} + +void returnVoid(int x, int y) { + return IntegerOps(x, y); +} + +void gccBinaryConditional(bool b, int x, long y) { + int z = x; + z = b ?: x; + z = b ?: y; + z = x ?: x; + z = x ?: y; + z = y ?: x; + z = y ?: y; + + z = (x && b || y) ?: x; +} + +bool predicateA(); +bool predicateB(); + +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 79% 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 735555b5a4b..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 @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -23,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 10ec2a63dc2..999df2c5202 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_6 -# 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,582 @@ 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() +# 1| Block 0 +# 1| v1_1(void) = EnterFunction : +# 1| mu1_2(unknown) = AliasedDefinition : +# 1| mu1_3(unknown) = InitializeNonLocal : +# 2| r2_1(glval<_Complex float>) = VariableAddress[cf] : +# 2| r2_2(double) = Constant[2.0] : +# 2| r2_3(_Complex float) = Convert : r2_2 +# 2| mu2_4(_Complex float) = Store : &:r2_1, r2_3 +# 3| r3_1(_Imaginary float) = Constant[1.0i] : +# 3| r3_2(_Complex float) = Convert : r3_1 +# 3| r3_3(glval<_Complex float>) = VariableAddress[cf] : +# 3| mu3_4(_Complex float) = Store : &:r3_3, r3_2 +# 4| r4_1(glval<_Complex double>) = VariableAddress[cd] : +# 4| r4_2(double) = Constant[3.0] : +# 4| r4_3(_Complex double) = Convert : r4_2 +# 4| mu4_4(_Complex double) = Store : &:r4_1, r4_3 +# 5| r5_1(_Imaginary float) = Constant[1.0i] : +# 5| r5_2(_Complex double) = Convert : r5_1 +# 5| r5_3(glval<_Complex double>) = VariableAddress[cd] : +# 5| mu5_4(_Complex double) = Store : &:r5_3, r5_2 +# 6| r6_1(glval<_Complex long double>) = VariableAddress[cld] : +# 6| r6_2(double) = Constant[5.0] : +# 6| r6_3(_Complex long double) = Convert : r6_2 +# 6| mu6_4(_Complex long double) = Store : &:r6_1, r6_3 +# 7| r7_1(_Imaginary float) = Constant[1.0i] : +# 7| r7_2(_Complex long double) = Convert : r7_1 +# 7| r7_3(glval<_Complex long double>) = VariableAddress[cld] : +# 7| mu7_4(_Complex long double) = Store : &:r7_3, r7_2 +# 9| r9_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 9| r9_2(_Imaginary float) = Constant[1.0i] : +# 9| mu9_3(_Imaginary float) = Store : &:r9_1, r9_2 +# 10| r10_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 10| r10_2(_Imaginary float) = Constant[1.0i] : +# 10| r10_3(_Imaginary double) = Convert : r10_2 +# 10| mu10_4(_Imaginary double) = Store : &:r10_1, r10_3 +# 11| r11_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 11| r11_2(_Imaginary float) = Constant[1.0i] : +# 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_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 : +# 15| r15_1(glval) = VariableAddress[f1] : +# 15| r15_2(float) = Constant[5.0] : +# 15| mu15_3(float) = Store : &:r15_1, r15_2 +# 16| r16_1(glval) = VariableAddress[f2] : +# 16| r16_2(float) = Constant[7.0] : +# 16| mu16_3(float) = Store : &:r16_1, r16_2 +# 17| r17_1(glval) = VariableAddress[f3] : +# 17| mu17_2(float) = Uninitialized[f3] : &:r17_1 +# 18| r18_1(glval<_Complex float>) = VariableAddress[cf1] : +# 18| r18_2(double) = Constant[2.0] : +# 18| r18_3(_Complex float) = Convert : r18_2 +# 18| mu18_4(_Complex float) = Store : &:r18_1, r18_3 +# 19| r19_1(glval<_Complex float>) = VariableAddress[cf2] : +# 19| r19_2(_Imaginary float) = Constant[1.0i] : +# 19| r19_3(_Complex float) = Convert : r19_2 +# 19| mu19_4(_Complex float) = Store : &:r19_1, r19_3 +# 20| r20_1(glval<_Complex float>) = VariableAddress[cf3] : +# 20| mu20_2(_Complex float) = Uninitialized[cf3] : &:r20_1 +# 21| r21_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 21| r21_2(_Imaginary float) = Constant[1.0i] : +# 21| mu21_3(_Imaginary float) = Store : &:r21_1, r21_2 +# 22| r22_1(glval<_Imaginary float>) = VariableAddress[jf2] : +# 22| r22_2(_Imaginary float) = Constant[1.0i] : +# 22| mu22_3(_Imaginary float) = Store : &:r22_1, r22_2 +# 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, ~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, ~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, ~m? +# 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] : +# 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, ~m? +# 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] : +# 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, ~m? +# 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] : +# 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, ~m? +# 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] : +# 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, ~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, ~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, ~m? +# 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 46| r46_3(glval) = VariableAddress[f2] : +# 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, ~m? +# 47| r47_3(glval) = VariableAddress[f2] : +# 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, ~m? +# 48| r48_3(glval) = VariableAddress[f2] : +# 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, ~m? +# 49| r49_3(glval) = VariableAddress[f2] : +# 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, ~m? +# 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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, ~m? +# 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 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_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 : +# 59| r59_1(glval) = VariableAddress[f] : +# 59| r59_2(float) = Constant[2.0] : +# 59| mu59_3(float) = Store : &:r59_1, r59_2 +# 60| r60_1(glval) = VariableAddress[d] : +# 60| r60_2(double) = Constant[3.0] : +# 60| mu60_3(double) = Store : &:r60_1, r60_2 +# 61| r61_1(glval) = VariableAddress[ld] : +# 61| r61_2(long double) = Constant[5.0] : +# 61| mu61_3(long double) = Store : &:r61_1, r61_2 +# 62| r62_1(glval<_Complex float>) = VariableAddress[cf] : +# 62| r62_2(double) = Constant[7.0] : +# 62| r62_3(_Complex float) = Convert : r62_2 +# 62| mu62_4(_Complex float) = Store : &:r62_1, r62_3 +# 63| r63_1(glval<_Complex double>) = VariableAddress[cd] : +# 63| r63_2(double) = Constant[11.0] : +# 63| r63_3(_Complex double) = Convert : r63_2 +# 63| mu63_4(_Complex double) = Store : &:r63_1, r63_3 +# 64| r64_1(glval<_Complex long double>) = VariableAddress[cld] : +# 64| r64_2(double) = Constant[13.0] : +# 64| r64_3(_Complex long double) = Convert : r64_2 +# 64| mu64_4(_Complex long double) = Store : &:r64_1, r64_3 +# 65| r65_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 65| r65_2(_Imaginary float) = Constant[1.0i] : +# 65| mu65_3(_Imaginary float) = Store : &:r65_1, r65_2 +# 66| r66_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 66| r66_2(_Imaginary float) = Constant[1.0i] : +# 66| r66_3(_Imaginary double) = Convert : r66_2 +# 66| mu66_4(_Imaginary double) = Store : &:r66_1, r66_3 +# 67| r67_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 67| r67_2(_Imaginary float) = Constant[1.0i] : +# 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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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, ~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_4(void) = ReturnVoid : +# 58| v58_5(void) = AliasedUse : ~m? +# 58| v58_6(void) = ExitFunction : ir.cpp: # 1| void Constants() @@ -130,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 @@ -216,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 @@ -426,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 @@ -524,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 @@ -532,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 @@ -557,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 @@ -566,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 @@ -748,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 @@ -756,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_6 -# 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_6 -# 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] : @@ -893,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"] : @@ -952,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_6 -# 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_10 -# 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_6 -# 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 @@ -1065,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 @@ -1073,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 @@ -1221,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 : @@ -1235,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 @@ -1269,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 @@ -1289,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 : @@ -1317,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 : @@ -1338,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 @@ -1362,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 @@ -1419,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 @@ -1474,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 @@ -1510,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 @@ -1545,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 @@ -1566,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 @@ -1593,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 @@ -1608,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 @@ -1642,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 @@ -1659,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_6 -# 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 @@ -1733,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 @@ -1760,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 @@ -1781,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 @@ -1789,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 @@ -1797,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 @@ -1948,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] : @@ -1987,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 @@ -1997,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 @@ -2035,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 @@ -2061,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 @@ -2099,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 @@ -2125,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 @@ -2156,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 @@ -2182,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 @@ -2220,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 @@ -2237,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 @@ -2250,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] : @@ -2268,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 @@ -2281,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 @@ -2301,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] : @@ -2385,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 @@ -2397,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] : @@ -2482,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 @@ -2510,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 @@ -2525,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] : @@ -2547,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] : @@ -2555,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] : @@ -2587,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] : @@ -2604,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 : @@ -2670,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 : @@ -2681,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 @@ -2724,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 @@ -2757,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 : @@ -2789,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 @@ -2841,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 @@ -2859,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 @@ -2895,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 @@ -2918,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 @@ -2933,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_6 -# 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_10 -# 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_6 -# 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] : @@ -3267,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 @@ -3329,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_6 -# 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 @@ -3451,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 @@ -3465,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 @@ -3475,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 @@ -3487,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 @@ -3508,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, ~mu735_3 +# 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 @@ -3531,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, ~mu738_3 +# 738| r738_4(String &) = Load : &:r738_2, ~m? # 738| mu738_5(unknown) = InitializeIndirection[e] : &:r738_4 # 738| v738_6(void) = NoOp : #-----| Goto -> Block 14 @@ -3542,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, ~mu0_2 -#-----| 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, ~mu0_2 +#-----| 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, ~mu0_2 +#-----| 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, ~mu0_2 +#-----| 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] : @@ -4035,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 @@ -4048,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 @@ -4068,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 @@ -4108,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 @@ -4121,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 @@ -4149,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 @@ -4163,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 @@ -4184,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 @@ -4228,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 @@ -4242,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 @@ -4272,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] : @@ -4362,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 @@ -4372,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 @@ -4383,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_3(PolymorphicBase *) = Load : &:r863_2, ~m? # 863| r863_4(void *) = DynamicCastToVoid : 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_3(PolymorphicDerived *) = Load : &:r864_2, ~m? # 864| r864_4(void *) = DynamicCastToVoid : 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] : @@ -4468,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_8 -# 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_8 -# 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_8 -# 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] : @@ -4574,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] : @@ -4602,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 @@ -4653,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 @@ -4680,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] : @@ -4705,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] : @@ -4739,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[]] : @@ -4811,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] : @@ -4873,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 @@ -4914,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 @@ -4940,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 @@ -4951,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 @@ -4982,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 @@ -5006,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 @@ -5020,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 @@ -5045,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_6 -# 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 @@ -5097,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_8 -# 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 @@ -5346,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 @@ -5364,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_6 -# 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 @@ -5728,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 @@ -5772,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) @@ -5816,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_6 -# 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_12 -# 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 @@ -5906,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 @@ -5915,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 @@ -5951,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 @@ -5965,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 @@ -5975,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 @@ -5987,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 @@ -6008,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, ~mu1153_3 +# 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 @@ -6031,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, ~mu1156_3 +# 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) @@ -6046,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] : @@ -6070,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] : @@ -6124,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 @@ -6185,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 @@ -6228,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 @@ -6273,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 @@ -6326,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 @@ -6351,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 @@ -6382,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_6 -# 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 @@ -6406,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 @@ -6416,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 @@ -6425,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 @@ -6437,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 @@ -6458,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_6 -# 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_10 -# 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] : @@ -6481,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_6 -# 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_8 -# 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] : @@ -6563,119 +7014,470 @@ 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| 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, ~m? +# 1290| v1290_3(void) = ConditionalBranch : r1290_2 +#-----| False -> Block 1 +#-----| True -> Block 2 + +# 1293| Block 1 +# 1293| v1293_1(void) = Unreached : + +# 1291| Block 2 +# 1291| r1291_1(glval) = VariableAddress[#return] : +# 1291| r1291_2(glval) = VariableAddress[x] : +# 1291| r1291_3(int) = Load : &:r1291_2, ~m? +# 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 +# 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| 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, ~m? +# 1296| r1296_4(glval) = VariableAddress[y] : +# 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 : ~m? +# 1296| v1296_8(void) = NoOp : +# 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| 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, ~m? +# 1300| mu1300_4(int) = Store : &:r1300_1, r1300_3 +# 1301| r1301_1(glval) = VariableAddress[b] : +# 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, ~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, ~m? +# 1302| v1302_3(void) = ConditionalBranch : r1302_2 +#-----| False -> Block 6 +#-----| True -> Block 5 + +# 1301| Block 2 +# 1301| r1301_8(glval) = VariableAddress[#temp1301:9] : +# 1301| mu1301_9(int) = Store : &:r1301_8, r1301_2 +#-----| Goto -> Block 1 + +# 1301| Block 3 +# 1301| r1301_10(glval) = VariableAddress[x] : +# 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, ~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, ~m? +# 1303| r1303_3(int) = Constant[0] : +# 1303| r1303_4(bool) = CompareNE : r1303_2, r1303_3 +# 1303| v1303_5(void) = ConditionalBranch : r1303_4 +#-----| False -> Block 9 +#-----| True -> Block 8 + +# 1302| Block 5 +# 1302| r1302_9(glval) = VariableAddress[#temp1302:9] : +# 1302| mu1302_10(long) = Store : &:r1302_9, r1302_2 +#-----| Goto -> Block 4 + +# 1302| Block 6 +# 1302| r1302_11(glval) = VariableAddress[y] : +# 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, ~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, ~m? +# 1304| r1304_3(int) = Constant[0] : +# 1304| r1304_4(bool) = CompareNE : r1304_2, r1304_3 +# 1304| v1304_5(void) = ConditionalBranch : r1304_4 +#-----| False -> Block 12 +#-----| True -> Block 11 + +# 1303| Block 8 +# 1303| r1303_10(glval) = VariableAddress[#temp1303:9] : +# 1303| mu1303_11(int) = Store : &:r1303_10, r1303_2 +#-----| Goto -> Block 7 + +# 1303| Block 9 +# 1303| r1303_12(glval) = VariableAddress[x] : +# 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, ~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, ~m? +# 1305| r1305_3(long) = Constant[0] : +# 1305| r1305_4(bool) = CompareNE : r1305_2, r1305_3 +# 1305| v1305_5(void) = ConditionalBranch : r1305_4 +#-----| False -> Block 15 +#-----| True -> Block 14 + +# 1304| Block 11 +# 1304| r1304_11(glval) = VariableAddress[#temp1304:9] : +# 1304| mu1304_12(long) = Store : &:r1304_11, r1304_2 +#-----| Goto -> Block 10 + +# 1304| Block 12 +# 1304| r1304_13(glval) = VariableAddress[y] : +# 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, ~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, ~m? +# 1306| r1306_3(long) = Constant[0] : +# 1306| r1306_4(bool) = CompareNE : r1306_2, r1306_3 +# 1306| v1306_5(void) = ConditionalBranch : r1306_4 +#-----| False -> Block 18 +#-----| True -> Block 17 + +# 1305| Block 14 +# 1305| r1305_11(glval) = VariableAddress[#temp1305:9] : +# 1305| mu1305_12(long) = Store : &:r1305_11, r1305_2 +#-----| Goto -> Block 13 + +# 1305| Block 15 +# 1305| r1305_13(glval) = VariableAddress[x] : +# 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 +#-----| Goto -> Block 13 + +# 1306| Block 16 +# 1306| r1306_6(glval) = VariableAddress[#temp1306:9] : +# 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, ~m? +# 1308| r1308_3(int) = Constant[0] : +# 1308| r1308_4(bool) = CompareNE : r1308_2, r1308_3 +# 1308| v1308_5(void) = ConditionalBranch : r1308_4 +#-----| False -> Block 25 +#-----| True -> Block 24 + +# 1306| Block 17 +# 1306| r1306_11(glval) = VariableAddress[#temp1306:9] : +# 1306| mu1306_12(long) = Store : &:r1306_11, r1306_2 +#-----| Goto -> Block 16 + +# 1306| Block 18 +# 1306| r1306_13(glval) = VariableAddress[y] : +# 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, ~m? +# 1308| r1308_8(glval) = VariableAddress[z] : +# 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 +# 1309| v1309_1(void) = NoOp : +# 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] : +# 1308| mu1308_11(int) = Store : &:r1308_10, r1308_16 +#-----| Goto -> Block 19 + +# 1308| Block 21 +# 1308| r1308_12(glval) = VariableAddress[#temp1308:10] : +# 1308| r1308_13(bool) = Constant[0] : +# 1308| mu1308_14(bool) = Store : &:r1308_12, r1308_13 +#-----| Goto -> Block 22 + +# 1308| Block 22 +# 1308| r1308_15(glval) = VariableAddress[#temp1308:10] : +# 1308| r1308_16(bool) = Load : &:r1308_15, ~m? +# 1308| v1308_17(void) = ConditionalBranch : r1308_16 +#-----| False -> Block 26 +#-----| True -> Block 20 + +# 1308| Block 23 +# 1308| r1308_18(glval) = VariableAddress[#temp1308:10] : +# 1308| r1308_19(bool) = Constant[1] : +# 1308| mu1308_20(bool) = Store : &:r1308_18, r1308_19 +#-----| Goto -> Block 22 + +# 1308| Block 24 +# 1308| r1308_21(glval) = VariableAddress[b] : +# 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, ~m? +# 1308| r1308_26(long) = Constant[0] : +# 1308| r1308_27(bool) = CompareNE : r1308_25, r1308_26 +# 1308| v1308_28(void) = ConditionalBranch : r1308_27 +#-----| False -> Block 21 +#-----| True -> Block 23 + +# 1308| Block 26 +# 1308| r1308_29(glval) = VariableAddress[x] : +# 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 + +# 1314| int shortCircuitConditional(int, int) +# 1314| Block 0 +# 1314| v1314_1(void) = EnterFunction : +# 1314| mu1314_2(unknown) = AliasedDefinition : +# 1314| mu1314_3(unknown) = InitializeNonLocal : +# 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 : ~m? +# 1315| v1315_5(void) = ConditionalBranch : r1315_3 +#-----| False -> Block 3 +#-----| True -> Block 1 + +# 1315| Block 1 +# 1315| r1315_6(glval) = FunctionAddress[predicateB] : +# 1315| r1315_7(bool) = Call : func:r1315_6 +# 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, ~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, ~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, ~m? +# 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 +# 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*) @@ -6683,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_6 -# 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] : @@ -6749,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_6 -# 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 @@ -6779,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] : @@ -6795,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 79% 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 735555b5a4b..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 @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -23,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 735555b5a4b..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected +++ /dev/null @@ -1,30 +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 -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 89% 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 1e78ae87f40..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 @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -19,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 89% 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 1e78ae87f40..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 @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -19,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 89002a5d3ca..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected +++ /dev/null @@ -1,28 +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 -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 89% 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 1e78ae87f40..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 @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -19,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/ir/types/complex.c b/cpp/ql/test/library-tests/ir/types/complex.c new file mode 100644 index 00000000000..450f5de9e65 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/types/complex.c @@ -0,0 +1,15 @@ +void Complex(void) { + _Complex float cf; //$irtype=cfloat8 + _Complex double cd; //$irtype=cfloat16 + _Complex long double cld; //$irtype=cfloat32 + // _Complex __float128 cf128; +} + +void Imaginary(void) { + _Imaginary float jf; //$irtype=ifloat4 + _Imaginary double jd; //$irtype=ifloat8 + _Imaginary long double jld; //$irtype=ifloat16 + // _Imaginary __float128 jf128; +} + +// semmle-extractor-options: --microsoft --edg --c99 diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.cpp b/cpp/ql/test/library-tests/ir/types/irtypes.cpp new file mode 100644 index 00000000000..321382567b7 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/types/irtypes.cpp @@ -0,0 +1,65 @@ +struct A { + int f_a; +}; + +struct B { + double f_a; + float f_b; +}; + +enum E { + Zero, + One, + Two, + Three +}; + +enum class ScopedE { + Zero, + One, + Two, + Three +}; + +void IRTypes() { + char c; //$irtype=int1 + signed char sc; //$irtype=int1 + unsigned char uc; //$irtype=uint1 + short s; //$irtype=int2 + signed short ss; //$irtype=int2 + unsigned short us; //$irtype=uint2 + int i; //$irtype=int4 + signed int si; //$irtype=int4 + unsigned int ui; //$irtype=uint4 + long l; //$irtype=int8 + signed long sl; //$irtype=int8 + unsigned long ul; //$irtype=uint8 + long long ll; //$irtype=int8 + signed long long sll; //$irtype=int8 + unsigned long long ull; //$irtype=uint8 + bool b; //$irtype=bool1 + float f; //$irtype=float4 + double d; //$irtype=float8 + long double ld; //$irtype=float16 + __float128 f128; //$irtype=float16 + + wchar_t wc; //$irtype=uint4 +// char8_t c8; //$irtype=uint1 + char16_t c16; //$irtype=uint2 + char32_t c32; //$irtype=uint4 + + int* pi; //$irtype=addr8 + int& ri = i; //$irtype=addr8 + void (*pfn)() = nullptr; //$irtype=func8 + void (&rfn)() = IRTypes; //$irtype=func8 + + A s_a; //$irtype=opaque4{A} + B s_b; //$irtype=opaque16{B} + + E e; //$irtype=uint4 + ScopedE se; //$irtype=uint4 + + B a_b[10]; //$irtype=opaque160{B[10]} +} + +// semmle-extractor-options: -std=c++17 --clang diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.expected b/cpp/ql/test/library-tests/ir/types/irtypes.expected similarity index 100% rename from python/ql/test/library-tests/PointsTo/new/Sanity.expected rename to cpp/ql/test/library-tests/ir/types/irtypes.expected diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.ql b/cpp/ql/test/library-tests/ir/types/irtypes.ql new file mode 100644 index 00000000000..56a7666458b --- /dev/null +++ b/cpp/ql/test/library-tests/ir/types/irtypes.ql @@ -0,0 +1,18 @@ +private import cpp +private import semmle.code.cpp.ir.implementation.raw.IR +import TestUtilities.InlineExpectationsTest + +class IRTypesTest extends InlineExpectationsTest { + IRTypesTest() { this = "IRTypesTest" } + + override string getARelevantTag() { result = "irtype" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(IRUserVariable irVar | + location = irVar.getLocation() and + element = irVar.toString() and + tag = "irtype" and + value = irVar.getIRType().toString() + ) + } +} diff --git a/cpp/ql/test/library-tests/lambdas/captures/elements.expected b/cpp/ql/test/library-tests/lambdas/captures/elements.expected index 1720fa2ca8e..feeadc7a604 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 | ..()(..) | @@ -292,17 +305,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/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/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected index be768a4a82f..78ff3edde3d 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected @@ -35,7 +35,7 @@ | test.cpp:97:10:97:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 | | test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 | | test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 | -| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 | +| test.cpp:117:10:117:10 | Load: i | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:116:7:116:11 | test.cpp:116:7:116:11 | | test.cpp:130:10:130:10 | Load: i | file://:0:0:0:0 | 0 | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | | test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 | | test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp index d31de1d2b80..87653c2fa43 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp +++ b/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp @@ -104,7 +104,7 @@ void test9(int x) { } // Phi nodes as bounds -int test10(int y, int z, bool use_y) { +void test10(int y, int z, bool use_y) { int x; if(use_y) { x = y; @@ -112,9 +112,9 @@ int test10(int y, int z, bool use_y) { x = z; } sink(); - for(int i = 0; i < x; i++) { - return i; - } + int i = source(); + if (i < x) + sink(i); } // Irreducible CFGs diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected index 0caa5a5b692..438bc9173f2 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected @@ -512,32 +512,40 @@ | test.c:367:15:367:17 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:368:5:368:21 | Store: ... = ... | positive strictlyPositive | | test.c:368:10:368:21 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:368:10:368:21 | Phi: ... ? ... : ... | positive strictlyPositive | +| test.c:368:10:368:21 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:368:10:368:21 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:368:11:368:11 | Load: x | positive | | test.c:368:11:368:13 | Add: ... + ... | positive strictlyPositive | | test.c:368:13:368:13 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:368:19:368:21 | Constant: (unsigned int)... | positive strictlyPositive | -| test.c:369:5:369:36 | Store: ... = ... | positive strictlyPositive | -| test.c:369:10:369:36 | Convert: (unsigned int)... | positive strictlyPositive | -| test.c:369:10:369:36 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:369:5:369:36 | Store: ... = ... | positive | +| test.c:369:10:369:36 | Convert: (unsigned int)... | positive | +| test.c:369:10:369:36 | Load: ... ? ... : ... | positive | +| test.c:369:10:369:36 | Phi: ... ? ... : ... | positive | +| test.c:369:10:369:36 | Store: ... ? ... : ... | positive | | test.c:369:10:369:36 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:369:11:369:30 | Convert: (unsigned char)... | positive | | test.c:369:27:369:27 | Load: x | positive | | test.c:369:27:369:29 | Add: ... + ... | positive strictlyPositive | | test.c:369:29:369:29 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:369:36:369:36 | Constant: 5 | positive strictlyPositive | -| test.c:370:5:370:38 | Store: ... = ... | positive strictlyPositive | -| test.c:370:10:370:38 | Convert: (unsigned int)... | positive strictlyPositive | -| test.c:370:10:370:38 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:370:5:370:38 | Store: ... = ... | positive | +| test.c:370:10:370:38 | Convert: (unsigned int)... | positive | +| test.c:370:10:370:38 | Load: ... ? ... : ... | positive | +| test.c:370:10:370:38 | Phi: ... ? ... : ... | positive | +| test.c:370:10:370:38 | Store: ... ? ... : ... | positive | | test.c:370:10:370:38 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:370:11:370:30 | Convert: (unsigned char)... | positive | | test.c:370:27:370:27 | Load: x | positive | | test.c:370:27:370:29 | Add: ... + ... | positive strictlyPositive | | test.c:370:29:370:29 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:370:36:370:38 | Constant: 500 | positive strictlyPositive | -| test.c:371:5:371:39 | Store: ... = ... | positive strictlyPositive | -| test.c:371:10:371:39 | Convert: (unsigned int)... | positive strictlyPositive | -| test.c:371:10:371:39 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:371:5:371:39 | Store: ... = ... | positive | +| test.c:371:10:371:39 | Convert: (unsigned int)... | positive | +| test.c:371:10:371:39 | Load: ... ? ... : ... | positive | +| test.c:371:10:371:39 | Phi: ... ? ... : ... | positive | +| test.c:371:10:371:39 | Store: ... ? ... : ... | positive | | test.c:371:10:371:39 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:371:11:371:31 | Convert: (unsigned short)... | positive | | test.c:371:28:371:28 | Load: x | positive | @@ -598,32 +606,38 @@ | test.c:383:8:383:11 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:384:7:384:7 | Load: x | positive | | test.c:384:12:384:14 | Constant: (unsigned int)... | positive strictlyPositive | -| test.c:385:5:385:21 | Store: ... = ... | positive strictlyPositive | -| test.c:385:10:385:21 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:385:5:385:21 | Store: ... = ... | positive | +| test.c:385:10:385:21 | Load: ... ? ... : ... | positive | +| test.c:385:10:385:21 | Phi: ... ? ... : ... | positive | +| test.c:385:10:385:21 | Store: ... ? ... : ... | positive | | test.c:385:10:385:21 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:385:11:385:11 | Load: x | positive strictlyPositive | | test.c:385:11:385:15 | Sub: ... - ... | positive | | test.c:385:13:385:15 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:385:21:385:21 | Constant: (unsigned int)... | positive strictlyPositive | -| test.c:386:5:386:21 | Store: ... = ... | positive strictlyPositive | -| test.c:386:10:386:21 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:386:5:386:21 | Store: ... = ... | positive | +| test.c:386:10:386:21 | Load: ... ? ... : ... | positive | +| test.c:386:10:386:21 | Phi: ... ? ... : ... | positive | +| test.c:386:10:386:21 | Store: ... ? ... : ... | positive | | test.c:386:10:386:21 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:386:11:386:11 | Load: x | positive strictlyPositive | | test.c:386:11:386:15 | Sub: ... - ... | positive | | test.c:386:13:386:15 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:386:21:386:21 | Constant: (unsigned int)... | positive strictlyPositive | -| test.c:387:5:387:38 | Store: ... = ... | positive strictlyPositive | -| test.c:387:10:387:38 | Convert: (unsigned int)... | positive strictlyPositive | -| test.c:387:10:387:38 | Load: ... ? ... : ... | positive strictlyPositive | +| test.c:387:5:387:38 | Store: ... = ... | positive | +| test.c:387:10:387:38 | Convert: (unsigned int)... | positive | +| test.c:387:10:387:38 | Load: ... ? ... : ... | positive | +| test.c:387:10:387:38 | Phi: ... ? ... : ... | positive | +| test.c:387:10:387:38 | Store: ... ? ... : ... | positive | | test.c:387:10:387:38 | Store: ... ? ... : ... | positive strictlyPositive | | test.c:387:11:387:32 | Convert: (unsigned char)... | positive | | test.c:387:27:387:27 | Load: x | positive strictlyPositive | | test.c:387:27:387:31 | Sub: ... - ... | positive | | test.c:387:29:387:31 | Constant: (unsigned int)... | positive strictlyPositive | | test.c:387:38:387:38 | Constant: 5 | positive strictlyPositive | -| test.c:389:3:389:32 | Phi: return ... | positive strictlyPositive | -| test.c:389:3:389:32 | Phi: return ... | positive strictlyPositive | -| test.c:389:3:389:32 | Phi: return ... | positive strictlyPositive | +| test.c:389:3:389:32 | Phi: return ... | positive | +| test.c:389:3:389:32 | Phi: return ... | positive | +| test.c:389:3:389:32 | Phi: return ... | positive | | test.c:389:10:389:11 | Load: y1 | positive strictlyPositive | | test.c:389:10:389:16 | Add: ... + ... | positive strictlyPositive | | test.c:389:10:389:21 | Add: ... + ... | positive strictlyPositive | @@ -631,9 +645,9 @@ | test.c:389:10:389:31 | Add: ... + ... | positive strictlyPositive | | test.c:389:10:389:31 | Store: ... + ... | positive strictlyPositive | | test.c:389:15:389:16 | Load: y2 | positive strictlyPositive | -| test.c:389:20:389:21 | Load: y3 | positive strictlyPositive | -| test.c:389:25:389:26 | Load: y4 | positive strictlyPositive | -| test.c:389:30:389:31 | Load: y5 | positive strictlyPositive | +| test.c:389:20:389:21 | Load: y3 | positive | +| test.c:389:25:389:26 | Load: y4 | positive | +| test.c:389:30:389:31 | Load: y5 | positive | | test.c:393:40:393:40 | InitializeParameter: x | positive | | test.c:394:20:394:20 | Load: x | positive | | test.c:394:20:394:36 | Load: ... ? ... : ... | positive | 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/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 362983363cc..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ /dev/null @@ -1,578 +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 -| cpp11.cpp:141:7:141:7 | Phi: g | cpp11.cpp:161:16:161:16 | NoOp: label ...: | -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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | 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 | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:13:94:13 | ConditionalBranch: 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | Load: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | VariableAddress: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | Load: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | FieldAddress: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | Load: i | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | VariableAddress: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | -unnecessaryPhiInstruction -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -| misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:15:93:15 | Constant: 2 | -| misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:94:19:94:19 | VariableAddress: i | -| range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:15:366:15 | Constant: (unsigned int)... | -| range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | VariableAddress: x | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:15:367:17 | Constant: (unsigned int)... | -| range_analysis.c:368:19:368:21 | Constant: (unsigned int)... | -| range_analysis.c:369:36:369:36 | Constant: 5 | -| range_analysis.c:370:36:370:38 | Constant: 500 | -| range_analysis.c:371:37:371:39 | Constant: 500 | -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..6b0256c95f5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -31,28 +31,18 @@ uniqueTypeRepr 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 +82,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 b569b63cb61..dd2598dc9f8 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,11 +1,5 @@ uniqueEnclosingCallable uniqueTypeBound -| break_labels.c:13:5:13:18 | VariableAddress | Node should have one type bound but has 2. | -| break_labels.c:13:12:13:17 | Store | Node should have one type bound but has 2. | -| enum.c:6:2:6:10 | VariableAddress | Node should have one type bound but has 2. | -| enum.c:6:9:6:9 | Store | Node should have one type bound but has 2. | -| parameterinitializer.cpp:4:5:4:13 | VariableAddress | Node should have one type bound but has 2. | -| parameterinitializer.cpp:4:12:4:12 | Store | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | @@ -16,8 +10,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -28,8 +20,6 @@ uniqueNodeLocation | 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 | 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. | @@ -39,8 +29,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -49,8 +37,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -59,8 +45,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -75,8 +59,6 @@ uniqueNodeLocation | 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 | 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: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. | @@ -85,8 +67,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -97,8 +77,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -111,8 +89,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -121,8 +97,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -131,8 +105,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -141,8 +113,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -150,8 +120,6 @@ uniqueNodeLocation | 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 | 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. | @@ -160,14 +128,11 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -176,8 +141,6 @@ uniqueNodeLocation | 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. | | 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. | @@ -186,8 +149,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -202,8 +163,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -213,8 +172,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -224,8 +181,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -235,8 +190,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -247,9 +200,7 @@ uniqueNodeLocation | 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 | 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. | +| file://:0:0:0:0 | *p#2 | 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 | VariableAddress | Node should have one location but has 0. | @@ -287,8 +238,6 @@ uniqueNodeLocation | 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 | 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: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. | @@ -297,8 +246,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -307,8 +254,6 @@ uniqueNodeLocation | 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 | 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. | @@ -317,8 +262,6 @@ uniqueNodeLocation | 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 | 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. | @@ -327,8 +270,6 @@ uniqueNodeLocation | 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 | 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. | @@ -337,8 +278,6 @@ uniqueNodeLocation | 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 | 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. | @@ -347,8 +286,6 @@ uniqueNodeLocation | 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: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. | @@ -362,8 +299,6 @@ uniqueNodeLocation | 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 | 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. | @@ -372,8 +307,6 @@ uniqueNodeLocation | 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 | 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. | @@ -382,8 +315,6 @@ uniqueNodeLocation | 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 | 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. | @@ -392,8 +323,6 @@ uniqueNodeLocation | 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 | 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. | @@ -402,8 +331,6 @@ uniqueNodeLocation | 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: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. | @@ -418,8 +345,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -429,8 +354,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -440,8 +363,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -451,8 +372,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -462,8 +381,6 @@ uniqueNodeLocation | 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 | 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_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. | @@ -475,8 +392,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -489,8 +404,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -500,8 +413,6 @@ uniqueNodeLocation | 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 | 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. | @@ -511,8 +422,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -526,8 +435,6 @@ uniqueNodeLocation | 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: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. | @@ -536,8 +443,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -547,8 +452,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -558,8 +461,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -570,8 +471,6 @@ uniqueNodeLocation | 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 | 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. | @@ -581,8 +480,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -591,8 +488,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -601,8 +496,6 @@ uniqueNodeLocation | 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. | | 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. | @@ -611,8 +504,6 @@ uniqueNodeLocation | 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 | 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_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. | @@ -624,8 +515,6 @@ uniqueNodeLocation | 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 | 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. | | 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. | @@ -635,8 +524,6 @@ uniqueNodeLocation | 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 | 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. | @@ -646,8 +533,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -657,8 +542,6 @@ uniqueNodeLocation | 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 | 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 | Unreached | Node should have one location but has 20. | | 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. | @@ -673,8 +556,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -684,8 +565,6 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -694,8 +573,6 @@ uniqueNodeLocation | 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 | 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. | @@ -704,8 +581,6 @@ uniqueNodeLocation | 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 | 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. | @@ -714,8 +589,6 @@ uniqueNodeLocation | 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 | 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. | @@ -724,14 +597,11 @@ uniqueNodeLocation | 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 | 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 | 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. | @@ -740,8 +610,6 @@ uniqueNodeLocation | 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. | missingLocation | Nodes without location: 30 | uniqueNodeToString @@ -767,8 +635,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. | @@ -786,7 +652,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 @@ -794,6 +659,10 @@ unreachableNodeCCtx localCallNodes 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. | +| 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 reverseRead 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 cd5366a0c73..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ /dev/null @@ -1,643 +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*) | -| range_analysis.c:368:10:368:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | -| range_analysis.c:369:10:369:36 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | -| range_analysis.c:370:10:370:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | -| range_analysis.c:371:10:371:39 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:355:14:355:27 | IR: test_ternary01 | unsigned int test_ternary01(unsigned int) | -| range_analysis.c:385:10:385:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:377:14:377:27 | IR: test_ternary02 | unsigned int test_ternary02(unsigned int) | -| range_analysis.c:386:10:386:21 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:377:14:377:27 | IR: test_ternary02 | unsigned int test_ternary02(unsigned int) | -| range_analysis.c:387:10:387:38 | Store: ... ? ... : ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | range_analysis.c:377:14:377:27 | IR: test_ternary02 | unsigned int test_ternary02(unsigned int) | -| 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 *)... | -| 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | 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 | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:13:94:13 | ConditionalBranch: 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | Load: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | VariableAddress: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | Load: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | FieldAddress: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | Load: i | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | VariableAddress: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | -unnecessaryPhiInstruction -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -| misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:15:93:15 | Constant: 2 | -| misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:94:19:94:19 | VariableAddress: i | -| range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:15:366:15 | Constant: (unsigned int)... | -| range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | VariableAddress: x | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:15:367:17 | Constant: (unsigned int)... | -| range_analysis.c:368:10:368:21 | VariableAddress: ... ? ... : ... | -| range_analysis.c:368:19:368:21 | Constant: (unsigned int)... | -| range_analysis.c:369:10:369:36 | VariableAddress: ... ? ... : ... | -| range_analysis.c:369:36:369:36 | Constant: 5 | -| range_analysis.c:370:10:370:38 | VariableAddress: ... ? ... : ... | -| range_analysis.c:370:36:370:38 | Constant: 500 | -| range_analysis.c:371:10:371:39 | VariableAddress: ... ? ... : ... | -| range_analysis.c:371:37:371:39 | Constant: 500 | -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 82b5f5ccef0..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ /dev/null @@ -1,587 +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 -| cpp11.cpp:141:7:141:7 | Phi: g | cpp11.cpp:161:16:161:16 | NoOp: label ...: | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:373:3:373:47 | Phi: return ... | range_analysis.c:371:37:371:39 | Constant: 500 | -| range_analysis.c:389:3:389:32 | Phi: return ... | range_analysis.c:387:38:387:38 | Constant: 5 | -| range_analysis.c:389:3:389:32 | Phi: return ... | range_analysis.c:387:38:387:38 | Constant: 5 | -| range_analysis.c:389:3:389:32 | Phi: return ... | range_analysis.c:387:38:387:38 | Constant: 5 | -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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 20 | 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 20 | 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 | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:9 | Load: j | Goto | 2 | misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | Load: i | Goto | 2 | misc.c:94:13:94:13 | ConditionalBranch: 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:10 | Load: x | Goto | 2 | range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | Load: x | Goto | 2 | range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| 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 | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 20 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | enum.c:6:2:6:10 | VariableAddress: return ... | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 20 | 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 -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | Load: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:93:9:93:9 | VariableAddress: j | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | Load: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | FieldAddress: i | -| misc.c:91:6:91:33 | gnuConditionalOmittedOperand | misc.c:94:13:94:13 | Load: i | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:366:10:366:10 | VariableAddress: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | Load: x | -| range_analysis.c:355:14:355:27 | test_ternary01 | range_analysis.c:367:10:367:10 | VariableAddress: x | -unnecessaryPhiInstruction -operandAcrossFunctions -instructionWithoutUniqueBlock -containsLoopOfForwardEdges -lostReachability -| misc.c:93:9:93:9 | ConditionalBranch: j | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:9:93:15 | VariableAddress: ... ? ... : ... | -| misc.c:93:15:93:15 | Constant: 2 | -| misc.c:94:9:94:10 | VariableAddress: sp | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:9:94:19 | VariableAddress: ... ? ... : ... | -| misc.c:94:13:94:13 | ConditionalBranch: i | -| misc.c:94:19:94:19 | VariableAddress: i | -| range_analysis.c:366:10:366:10 | ConditionalBranch: x | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:10:366:15 | VariableAddress: ... ? ... : ... | -| range_analysis.c:366:15:366:15 | Constant: (unsigned int)... | -| range_analysis.c:367:10:367:10 | ConditionalBranch: x | -| range_analysis.c:367:10:367:10 | VariableAddress: x | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:10:367:17 | VariableAddress: ... ? ... : ... | -| range_analysis.c:367:15:367:17 | Constant: (unsigned int)... | -| range_analysis.c:368:19:368:21 | Constant: (unsigned int)... | -| range_analysis.c:369:36:369:36 | Constant: 5 | -| range_analysis.c:370:36:370:38 | Constant: 500 | -| range_analysis.c:371:37:371:39 | Constant: 500 | -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 52af59bd1f7..516e1067f78 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -51,6 +51,7 @@ | file://:0:0:0:0 | auto | | file://:0:0:0:0 | bool | | file://:0:0:0:0 | char | +| 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 & | @@ -109,6 +110,7 @@ | file://:0:0:0:0 | int | | file://:0:0:0:0 | int & | | file://:0:0:0:0 | int * | +| file://:0:0:0:0 | is_consteval | | file://:0:0:0:0 | is_constexpr | | file://:0:0:0:0 | is_thread_local | | file://:0:0:0:0 | long | @@ -164,10 +166,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 | @@ -228,6 +226,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 | @@ -311,6 +311,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/templates/prototype_bodies/isdef_hasblock.ql b/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql index c9cccbf24ae..be844bcf185 100644 --- a/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql +++ b/cpp/ql/test/library-tests/templates/prototype_bodies/isdef_hasblock.ql @@ -3,6 +3,6 @@ import cpp // It should be the case that "f.isDefined()" is equivalent to "exists(f.getBlock())". from Function f, string isdef, string hasblock where - (if f.isDefined() then isdef = "defined" else isdef = "not defined") and + (if f.hasDefinition() then isdef = "defined" else isdef = "not defined") and (if exists(f.getBlock()) then hasblock = "has block" else hasblock = "no block") select f.getName(), isdef, hasblock diff --git a/cpp/ql/test/library-tests/templates/type_instantiations/types.expected b/cpp/ql/test/library-tests/templates/type_instantiations/types.expected index 94930e59b7f..08ded1e8711 100644 --- a/cpp/ql/test/library-tests/templates/type_instantiations/types.expected +++ b/cpp/ql/test/library-tests/templates/type_instantiations/types.expected @@ -23,6 +23,7 @@ | file://:0:0:0:0 | auto | | file://:0:0:0:0 | bool | | file://:0:0:0:0 | char | +| 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 | const __va_list_tag | diff --git a/cpp/ql/test/library-tests/type_sizes/type_sizes.expected b/cpp/ql/test/library-tests/type_sizes/type_sizes.expected index 287a713f2f0..bda42bbc982 100644 --- a/cpp/ql/test/library-tests/type_sizes/type_sizes.expected +++ b/cpp/ql/test/library-tests/type_sizes/type_sizes.expected @@ -44,6 +44,7 @@ | file://:0:0:0:0 | auto | | | file://:0:0:0:0 | bool | 1 | | file://:0:0:0:0 | char | 1 | +| file://:0:0:0:0 | char8_t | 1 | | file://:0:0:0:0 | char16_t | 2 | | file://:0:0:0:0 | char32_t | 4 | | file://:0:0:0:0 | char * | 8 | 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/types/integral_types/integral_type.expected b/cpp/ql/test/library-tests/types/integral_types/integral_type.expected index 3b6f9d09cb6..e82a538d842 100644 --- a/cpp/ql/test/library-tests/types/integral_types/integral_type.expected +++ b/cpp/ql/test/library-tests/types/integral_types/integral_type.expected @@ -20,3 +20,4 @@ | 37 | signed __int128 | signed | -------- | explicitlySigned | ------------------ | ---------------- | 16 | 16 | unsigned __int128 | | | 43 | char16_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 2 | 2 | | | | 44 | char32_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 4 | 4 | | | +| 51 | char8_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 1 | 1 | | | diff --git a/cpp/ql/test/library-tests/types/integral_types_ms/integral_type.expected b/cpp/ql/test/library-tests/types/integral_types_ms/integral_type.expected index 8f5ca495f7f..59611267350 100644 --- a/cpp/ql/test/library-tests/types/integral_types_ms/integral_type.expected +++ b/cpp/ql/test/library-tests/types/integral_types_ms/integral_type.expected @@ -20,3 +20,4 @@ | 37 | signed __int128 | signed | -------- | explicitlySigned | ------------------ | ---------------- | 16 | 16 | unsigned __int128 | | | 43 | char16_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 2 | 2 | | | | 44 | char32_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 4 | 4 | | | +| 51 | char8_t | ------ | -------- | ---------------- | ------------------ | ---------------- | 1 | 1 | | | diff --git a/cpp/ql/test/library-tests/unnamed/elements.expected b/cpp/ql/test/library-tests/unnamed/elements.expected index 936ffa7575a..8df7d4578a2 100644 --- a/cpp/ql/test/library-tests/unnamed/elements.expected +++ b/cpp/ql/test/library-tests/unnamed/elements.expected @@ -33,6 +33,7 @@ | file://:0:0:0:0 | auto | Other | | file://:0:0:0:0 | bool | Other | | file://:0:0:0:0 | char | Other | +| file://:0:0:0:0 | char8_t | Other | | file://:0:0:0:0 | char16_t | Other | | file://:0:0:0:0 | char32_t | Other | | file://:0:0:0:0 | const | Other | @@ -58,6 +59,7 @@ | file://:0:0:0:0 | int | Other | | file://:0:0:0:0 | int * | Other | | file://:0:0:0:0 | int[0] | Other | +| file://:0:0:0:0 | is_consteval | Other | | file://:0:0:0:0 | is_constexpr | Other | | file://:0:0:0:0 | is_thread_local | Other | | file://:0:0:0:0 | long | Other | diff --git a/cpp/ql/test/library-tests/unspecified_type/types/unspecified_type.expected b/cpp/ql/test/library-tests/unspecified_type/types/unspecified_type.expected index d9407d2b67e..5e142e3ecf7 100644 --- a/cpp/ql/test/library-tests/unspecified_type/types/unspecified_type.expected +++ b/cpp/ql/test/library-tests/unspecified_type/types/unspecified_type.expected @@ -24,6 +24,7 @@ | file://:0:0:0:0 | auto | auto | | file://:0:0:0:0 | bool | bool | | file://:0:0:0:0 | char | char | +| file://:0:0:0:0 | char8_t | char8_t | | file://:0:0:0:0 | char16_t | char16_t | | file://:0:0:0:0 | char32_t | char32_t | | file://:0:0:0:0 | const __va_list_tag | __va_list_tag | 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 70a1977367f..b5d59659460 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -1,80 +1,75 @@ test.cpp: -# 1| int test00(int, int) +# 1| void test00(int, int) # 1| Block 0 -# 1| v1_1(void) = EnterFunction : -# 1| m1_2(unknown) = AliasedDefinition : +# 1| v1_1(void) = EnterFunction : +# 1| m1_2(unknown) = AliasedDefinition : # 1| valnum = unique -# 1| m1_3(unknown) = InitializeNonLocal : +# 1| m1_3(unknown) = InitializeNonLocal : # 1| valnum = unique -# 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3 +# 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 -# 2| r2_1(glval) = VariableAddress[x] : +# 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 +# 2| m2_2(int) = Uninitialized[x] : &:r2_1 # 2| valnum = unique -# 2| r2_3(glval) = VariableAddress[y] : +# 2| r2_3(glval) = VariableAddress[y] : # 2| valnum = r2_3, r7_3 -# 2| m2_4(int) = Uninitialized[y] : &:r2_3 +# 2| m2_4(int) = Uninitialized[y] : &:r2_3 # 2| valnum = unique -# 3| r3_1(glval) = VariableAddress[b] : +# 3| r3_1(glval) = VariableAddress[b] : # 3| valnum = unique -# 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1 +# 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| 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| r5_5(int) = Add : r5_2, r5_4 +# 5| r5_1(glval) = VariableAddress[p0] : +# 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_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] : +# 5| r5_6(glval) = VariableAddress[x] : # 5| valnum = r2_1, r5_6, r6_6, r7_1 -# 5| m5_7(int) = Store : &:r5_6, r5_5 +# 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| 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| r6_5(int) = Add : r6_2, r6_4 +# 6| r6_1(glval) = VariableAddress[p0] : +# 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_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] : +# 6| r6_6(glval) = VariableAddress[x] : # 6| valnum = r2_1, r5_6, r6_6, r7_1 -# 6| m6_7(int) = Store : &:r6_6, r6_5 +# 6| m6_7(int) = Store : &:r6_6, r6_5 # 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 7| r7_1(glval) = VariableAddress[x] : +# 7| r7_1(glval) = VariableAddress[x] : # 7| valnum = r2_1, r5_6, r6_6, r7_1 -# 7| r7_2(int) = Load : &:r7_1, m6_7 +# 7| r7_2(int) = Load : &:r7_1, m6_7 # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 -# 7| r7_3(glval) = VariableAddress[y] : +# 7| r7_3(glval) = VariableAddress[y] : # 7| valnum = r2_3, r7_3 -# 7| m7_4(int) = Store : &:r7_3, r7_2 +# 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| r1_10(glval) = VariableAddress[#return] : -# 1| valnum = unique -# 1| v1_11(void) = ReturnValue : &:r1_10 -# 1| v1_12(void) = UnmodeledUse : mu* -# 1| v1_13(void) = AliasedUse : m1_3 -# 1| v1_14(void) = ExitFunction : +# 8| v8_1(void) = NoOp : +# 1| v1_9(void) = ReturnVoid : +# 1| v1_10(void) = AliasedUse : m1_3 +# 1| v1_11(void) = ExitFunction : -# 12| int test01(int, int) +# 12| void test01(int, int) # 12| Block 0 # 12| v12_1(void) = EnterFunction : # 12| m12_2(unknown) = AliasedDefinition : @@ -83,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 @@ -106,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] : @@ -126,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] : @@ -154,14 +147,11 @@ 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| r12_10(glval) = VariableAddress[#return] : -# 12| valnum = unique -# 12| v12_11(void) = ReturnValue : &:r12_10 -# 12| v12_12(void) = UnmodeledUse : mu* -# 12| v12_13(void) = AliasedUse : m12_3 -# 12| v12_14(void) = ExitFunction : +# 12| v12_9(void) = ReturnVoid : +# 12| v12_10(void) = AliasedUse : m12_3 +# 12| v12_11(void) = ExitFunction : -# 25| int test02(int, int) +# 25| void test02(int, int) # 25| Block 0 # 25| v25_1(void) = EnterFunction : # 25| m25_2(unknown) = AliasedDefinition : @@ -170,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 @@ -193,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] : @@ -220,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] : @@ -248,14 +236,11 @@ 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| r25_10(glval) = VariableAddress[#return] : -# 25| valnum = unique -# 25| v25_11(void) = ReturnValue : &:r25_10 -# 25| v25_12(void) = UnmodeledUse : mu* -# 25| v25_13(void) = AliasedUse : ~m30_4 -# 25| v25_14(void) = ExitFunction : +# 25| v25_9(void) = ReturnVoid : +# 25| v25_10(void) = AliasedUse : ~m30_4 +# 25| v25_11(void) = ExitFunction : -# 39| int test03(int, int, int*) +# 39| void test03(int, int, int*) # 39| Block 0 # 39| v39_1(void) = EnterFunction : # 39| m39_2(unknown) = AliasedDefinition : @@ -264,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 @@ -295,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] : @@ -317,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] : @@ -355,13 +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| r39_15(glval) = VariableAddress[#return] : -# 39| valnum = unique -# 39| v39_16(void) = ReturnValue : &:r39_15 -# 39| v39_17(void) = UnmodeledUse : mu* -# 39| v39_18(void) = AliasedUse : m39_3 -# 39| v39_19(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 @@ -372,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 @@ -406,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 @@ -423,37 +401,37 @@ 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 -# 56| m56_1(decltype(nullptr)) = Phi : from 2:m55_4, from 5:m56_23 +# 56| m56_1(char *) = Phi : from 2:m55_4, from 5:m56_23 # 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2 -# 56| r56_2(glval) = VariableAddress[ptr] : +# 56| r56_2(glval) = VariableAddress[ptr] : # 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 -# 56| r56_3(char *) = Load : &:r56_2, m56_1 +# 56| r56_3(char *) = Load : &:r56_2, m56_1 # 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2 -# 56| r56_4(char) = Load : &:r56_3, ~m49_4 +# 56| r56_4(char) = Load : &:r56_3, ~m49_4 # 56| valnum = r56_14, r56_4, r59_3 -# 56| r56_5(int) = Convert : r56_4 +# 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| r56_6(glval) = VariableAddress[str] : +# 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| r56_9(int) = Convert : r56_8 # 56| valnum = r53_5, r56_9 -# 56| r56_10(bool) = CompareNE : r56_5, r56_9 +# 56| r56_10(bool) = CompareNE : r56_5, r56_9 # 56| valnum = unique -# 56| v56_11(void) = ConditionalBranch : r56_10 +# 56| v56_11(void) = ConditionalBranch : r56_10 #-----| False -> Block 6 #-----| True -> Block 4 @@ -524,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 @@ -549,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 @@ -580,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 @@ -628,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 @@ -689,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() @@ -726,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] : @@ -741,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 @@ -764,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 @@ -806,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 @@ -835,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"] : @@ -846,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 @@ -940,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] : @@ -993,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 @@ -1007,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 @@ -1046,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 @@ -1083,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] : @@ -1114,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 @@ -1124,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] : @@ -1140,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/GlobalValueNumbering/test.cpp b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp index 3e878ac2356..dfef91006e3 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/test.cpp @@ -1,4 +1,4 @@ -int test00(int p0, int p1) { +void test00(int p0, int p1) { int x, y; unsigned char b; @@ -9,7 +9,7 @@ int test00(int p0, int p1) { int global01 = 1; -int test01(int p0, int p1) { +void test01(int p0, int p1) { int x, y; unsigned char b; @@ -22,7 +22,7 @@ int global02 = 2; void change_global02(); // Just a declaration -int test02(int p0, int p1) { +void test02(int p0, int p1) { int x, y; unsigned char b; @@ -36,7 +36,7 @@ int global03 = 3; void change_global03(); // Just a declaration -int test03(int p0, int p1, int* p2) { +void test03(int p0, int p1, int* p2) { int x, y; unsigned char b; 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/library-tests/variables/variables/types.expected b/cpp/ql/test/library-tests/variables/variables/types.expected index cdc8c42a762..712ec74c914 100644 --- a/cpp/ql/test/library-tests/variables/variables/types.expected +++ b/cpp/ql/test/library-tests/variables/variables/types.expected @@ -1,21 +1,21 @@ | ..()(..) | RoutineType | | | | | | ..(*)(..) | FunctionPointerType | | ..()(..) | | | -| _Complex __float128 | FloatingPointType | | | | | -| _Complex double | FloatingPointType | | | | | -| _Complex float | FloatingPointType | | | | | -| _Complex long double | FloatingPointType | | | | | +| _Complex __float128 | BinaryFloatingPointType, ComplexNumberType | | | | | +| _Complex double | BinaryFloatingPointType, ComplexNumberType | | | | | +| _Complex float | BinaryFloatingPointType, ComplexNumberType | | | | | +| _Complex long double | BinaryFloatingPointType, ComplexNumberType | | | | | | _Decimal32 | Decimal32Type | | | | | | _Decimal64 | Decimal64Type | | | | | | _Decimal128 | Decimal128Type | | | | | -| _Float32 | FloatingPointType | | | | | -| _Float32x | FloatingPointType | | | | | -| _Float64 | FloatingPointType | | | | | -| _Float64x | FloatingPointType | | | | | -| _Float128 | FloatingPointType | | | | | -| _Float128x | FloatingPointType | | | | | -| _Imaginary double | FloatingPointType | | | | | -| _Imaginary float | FloatingPointType | | | | | -| _Imaginary long double | FloatingPointType | | | | | +| _Float32 | BinaryFloatingPointType, RealNumberType | | | | | +| _Float32x | BinaryFloatingPointType, RealNumberType | | | | | +| _Float64 | BinaryFloatingPointType, RealNumberType | | | | | +| _Float64x | BinaryFloatingPointType, RealNumberType | | | | | +| _Float128 | BinaryFloatingPointType, RealNumberType | | | | | +| _Float128x | BinaryFloatingPointType, RealNumberType | | | | | +| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | | +| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | | +| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | | | __float128 | Float128Type | | | | | | __int128 | Int128Type | | | | | | __va_list_tag | DirectAccessHolder, MetricClass, Struct, StructLikeClass | | | | | @@ -27,6 +27,7 @@ | auto | AutoType | | | | | | bool | BoolType | | | | | | char | MicrosoftInt8Type, PlainCharType | | | | | +| char8_t | Char8Type | | | | | | char16_t | Char16Type | | | | | | char32_t | Char32Type | | | | | | char * | CharPointerType | | char | | | diff --git a/cpp/ql/test/query-tests/Critical/OverflowCalculated/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Critical/OverflowCalculated/NoSpaceForZeroTerminator.expected index e106945ffb5..be283b4b634 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowCalculated/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Critical/OverflowCalculated/NoSpaceForZeroTerminator.expected @@ -1,7 +1,9 @@ | tests1.cpp:26:21:26:26 | call to malloc | This allocation does not include space to null-terminate the string. | +| tests1.cpp:36:21:36:26 | call to malloc | This allocation does not include space to null-terminate the string. | | tests1.cpp:56:21:56:27 | call to realloc | This allocation does not include space to null-terminate the string. | | tests1.cpp:67:21:67:26 | call to malloc | This allocation does not include space to null-terminate the string. | | tests1.cpp:89:25:89:30 | call to malloc | This allocation does not include space to null-terminate the string. | +| tests1.cpp:109:25:109:30 | call to malloc | This allocation does not include space to null-terminate the string. | | tests3.cpp:25:21:25:31 | call to malloc | This allocation does not include space to null-terminate the string. | | tests3.cpp:30:21:30:31 | call to malloc | This allocation does not include space to null-terminate the string. | | tests3.cpp:53:17:53:44 | new[] | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Critical/OverflowCalculated/OverflowCalculated.expected b/cpp/ql/test/query-tests/Critical/OverflowCalculated/OverflowCalculated.expected index 5d847989e17..8fe99858e1a 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowCalculated/OverflowCalculated.expected +++ b/cpp/ql/test/query-tests/Critical/OverflowCalculated/OverflowCalculated.expected @@ -1 +1,2 @@ | tests2.cpp:34:4:34:9 | call to strcat | This buffer only contains enough room for 'str1' (copied on line 33) | +| tests2.cpp:52:4:52:9 | call to strcat | This buffer only contains enough room for 'str1' (copied on line 51) | diff --git a/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests1.cpp b/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests1.cpp index ce660ed0de8..a47679bafc2 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests1.cpp +++ b/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests1.cpp @@ -33,7 +33,7 @@ void tests1(int case_num) break; case 3: - buffer = (char *)malloc(strlen(str) * sizeof(char)); // BAD [NOT DETECTED] + buffer = (char *)malloc(strlen(str) * sizeof(char)); // BAD strcpy(buffer, str); break; @@ -106,7 +106,7 @@ void tests1(int case_num) break; case 105: - wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t)); // BAD [NOT DETECTED] + wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t)); // BAD wcscpy(wbuffer, wstr); break; diff --git a/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests2.cpp b/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests2.cpp index dea14262f74..696b566329a 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests2.cpp +++ b/cpp/ql/test/query-tests/Critical/OverflowCalculated/tests2.cpp @@ -47,7 +47,7 @@ void tests2(int case_num) break; case 4: - buffer = (char *)malloc((strlen(str1) + 1) * sizeof(char)); // BAD [NOT DETECTED] + buffer = (char *)malloc((strlen(str1) + 1) * sizeof(char)); // BAD strcpy(buffer, str1); strcat(buffer, str2); break; 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-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected index 1476b2c7d95..bb49a2a58d9 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected @@ -3,7 +3,9 @@ | test.c:16:20:16:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.c:64:20:64:25 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. | +| test.cpp:31:35:31:40 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:55:28:55:33 | call to malloc | This allocation does not include space to null-terminate the string. | | test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c index 2f06af7d42d..21dcad6f2fd 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.c @@ -60,7 +60,7 @@ void good2(char *str) { } void bad3(char *str) { - // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] + // BAD -- Not allocating space for '\0' terminator char *buffer = malloc(strlen(str) * sizeof(char)); strcpy(buffer, str); free(buffer); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp index 996938c6324..63b2b4e760a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp @@ -27,7 +27,7 @@ void bad1(wchar_t *wstr) { } void bad2(wchar_t *wstr) { - // BAD -- Not allocating space for '\0' terminator [NOT DETECTED] + // BAD -- Not allocating space for '\0' terminator wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t)); wcscpy(wbuffer, wstr); free(wbuffer); 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/ComparisonWithWiderType/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected new file mode 100644 index 00000000000..d04bff0a812 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.expected @@ -0,0 +1,15 @@ +| test.c:4:14:4:18 | ... < ... | Comparison between $@ of type char and $@ of wider type int. | test.c:3:7:3:7 | c | c | test.c:2:17:2:17 | x | x | +| test.c:9:14:9:18 | ... > ... | Comparison between $@ of type char and $@ of wider type int. | test.c:8:7:8:7 | c | c | test.c:7:17:7:17 | x | x | +| test.c:14:14:14:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:13:8:13:8 | s | s | test.c:12:17:12:17 | x | x | +| test.c:65:14:65:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:64:8:64:8 | s | s | test.c:63:17:63:17 | x | x | +| test.c:87:14:87:18 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:84:15:84:15 | x | x | +| test.c:91:14:91:23 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:91:18:91:23 | 65280 | 65280 | +| test.c:93:14:93:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type int. | test.c:83:16:83:16 | c | c | test.c:93:18:93:25 | 16711680 | 16711680 | +| test.c:95:14:95:27 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:95:18:95:27 | 4278190080 | 4278190080 | +| test.c:99:14:99:29 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:99:19:99:28 | ... & ... | ... & ... | +| test.c:101:14:101:31 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:101:19:101:30 | ... & ... | ... & ... | +| test.c:103:14:103:33 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:103:19:103:32 | ... & ... | ... & ... | +| test.c:105:14:105:25 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:105:19:105:24 | ... >> ... | ... >> ... | +| test.c:107:14:107:26 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:83:16:83:16 | c | c | test.c:107:19:107:25 | ... >> ... | ... >> ... | +| test.c:128:15:128:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | +| test.c:139:15:139:21 | ... < ... | Comparison between $@ of type unsigned char and $@ of wider type unsigned int. | test.c:121:16:121:17 | uc | uc | test.c:123:19:123:20 | sz | sz | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.qlref similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.qlref rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/ComparisonWithWiderType.qlref diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c new file mode 100644 index 00000000000..f0b7f445aeb --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test.c @@ -0,0 +1,147 @@ + +void test1 (int x) { + char c; + for (c = 0; c < x; c++) {} //BAD +} + +void test2 (int x) { + char c; + for (c = 0; x > c; c++) {} // BAD +} + +void test3 (int x) { + short s; + for (s = 0; s < x; s++) {} //BAD +} + +void runner() { // get range analysis to give large values to x in tests + test1(65536); + test2(65536); + test3(655360); + test7((unsigned long long)1<<48); + test8(65536); + test9(65536); + test10(65536); + +} + +void test4 () { + short s1; + short s2 = 200; + for (s1 = 0; s1 < s2; s1++) {} +} + +void test5 () { + short s1; + int x = 65536; + s1 < x; +} + +void test6() { + short s1; + for (s1 = 0; s1 < 0x0000ffff; s1++) {} +} + +void test7(long long l) { + int i; + for (i = 0; i < l; i++) {} +} + +void test8(int x) { + short s; + for (s = 256; s < x; x--) {} +} + + +void test9(int x) { + short s; + for (s = 256; s < x; ) { + x--; + } +} + +void test10(int x) { + short s; + for (s = 0; s < x; ) { // BAD + do + { + s++; + } while (0); + } +} + +extern const int const256; + +void test11() { + short s; + for(s = 0; s < const256; ++s) {} +} + +unsigned int get_a_uint(); + +void test12() { + unsigned char c; + unsigned int x; + + x = get_a_uint(); + for (c = 0; c < x; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF; c++) {} // GOOD + x = get_a_uint(); + for (c = 0; c < 0xFF00; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF0000; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < 0xFF000000; c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF); c++) {} // GOOD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF00); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF0000); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x & 0xFF000000); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 8); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 16); c++) {} // BAD + x = get_a_uint(); + for (c = 0; c < (x >> 24); c++) {} // GOOD (assuming 32-bit ints) + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF00) >> 8); c++) {} // GOOD + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF0000) >> 16); c++) {} // GOOD + x = get_a_uint(); + for (c = 0; c < ((x & 0xFF000000) >> 24); c++) {} // GOOD +} + +int get_an_int(); + +void test13() { + unsigned char uc; + int sx, sy; + unsigned ux, uy, sz; + + ux = get_a_uint(); + uy = get_a_uint(); + sz = ux & uy; + for (uc = 0; uc < sz; uc++) {} // BAD + + ux = get_a_uint(); + uy = get_a_uint(); + if (ux > 128) {ux = 128;} + sz = ux & uy; + for (uc = 0; uc < sz; uc++) {} // GOOD + + sx = get_an_int(); + sy = get_an_int(); + sz = (unsigned)sx & (unsigned)sy; + for (uc = 0; uc < sz; uc++) {} // BAD + + sx = get_an_int(); + sy = get_an_int(); + if (sx < 0) {sx = 0;} + if (sx > 128) {sx = 128;} + sz = (unsigned)sx & (unsigned)sy; + for (uc = 0; uc < sz; uc++) {} // GOOD +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test2.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test2.c similarity index 100% rename from cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test2.c rename to cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/ComparisonWithWiderType/test2.c 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 3847e91bbc8..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 @@ -5,12 +5,6 @@ edges | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | (unsigned long)... | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | @@ -33,42 +27,58 @@ edges | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | (unsigned long)... | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | -| test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | -| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | (unsigned long)... | -| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size | -| test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | (unsigned long)... | -| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size | -| test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:27 | size | | test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | | test.cpp:123:18:123:31 | (const char *)... | test.cpp:127:24:127:41 | ... * ... | -| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | (unsigned long)... | -| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | -| test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | -| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | (unsigned long)... | -| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size | -| test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:13 | size | | test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... | | test.cpp:132:19:132:32 | (const char *)... | test.cpp:134:10:134:27 | ... * ... | -| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | (unsigned long)... | -| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | -| test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | -| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | (unsigned long)... | -| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size | -| test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:14 | size | | test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... | | test.cpp:138:19:138:32 | (const char *)... | test.cpp:142:11:142:28 | ... * ... | +| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size | +| test.cpp:201:9:201:42 | Store | test.cpp:231:9:231:24 | call to get_tainted_size | +| test.cpp:201:14:201:19 | call to getenv | test.cpp:201:9:201:42 | Store | +| test.cpp:201:14:201:27 | (const char *)... | test.cpp:201:9:201:42 | Store | +| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s | +| test.cpp:214:23:214:23 | s | test.cpp:215:21:215:21 | s | +| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | +| test.cpp:220:21:220:21 | s | test.cpp:221:21:221:21 | s | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | (size_t)... | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:235:11:235:20 | (size_t)... | +| test.cpp:227:24:227:29 | call to getenv | test.cpp:237:10:237:19 | (size_t)... | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | (size_t)... | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | +| test.cpp:227:24:227:37 | (const char *)... | test.cpp:235:11:235:20 | (size_t)... | +| 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 | @@ -77,11 +87,6 @@ nodes | test.cpp:42:38:42:44 | tainted | semmle.label | tainted | | test.cpp:42:38:42:44 | tainted | semmle.label | tainted | | test.cpp:42:38:42:44 | tainted | semmle.label | tainted | -| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:43:38:43:44 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:43:38:43:44 | tainted | semmle.label | tainted | -| test.cpp:43:38:43:44 | tainted | semmle.label | tainted | -| test.cpp:43:38:43:44 | tainted | semmle.label | tainted | | test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | | test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | | test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | @@ -99,53 +104,86 @@ nodes | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | | test.cpp:52:35:52:60 | ... * ... | semmle.label | ... * ... | -| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:52:54:52:60 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:52:54:52:60 | tainted | semmle.label | tainted | -| test.cpp:52:54:52:60 | tainted | semmle.label | tainted | -| test.cpp:52:54:52:60 | tainted | semmle.label | tainted | | test.cpp:123:18:123:23 | call to getenv | semmle.label | call to getenv | | test.cpp:123:18:123:31 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:127:24:127:27 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:127:24:127:27 | size | semmle.label | size | -| test.cpp:127:24:127:27 | size | semmle.label | size | -| test.cpp:127:24:127:27 | size | semmle.label | size | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | | test.cpp:127:24:127:41 | ... * ... | semmle.label | ... * ... | | test.cpp:132:19:132:24 | call to getenv | semmle.label | call to getenv | | test.cpp:132:19:132:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:134:10:134:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:134:10:134:13 | size | semmle.label | size | -| test.cpp:134:10:134:13 | size | semmle.label | size | -| test.cpp:134:10:134:13 | size | semmle.label | size | | test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | | test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | | test.cpp:134:10:134:27 | ... * ... | semmle.label | ... * ... | | test.cpp:138:19:138:24 | call to getenv | semmle.label | call to getenv | | test.cpp:138:19:138:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:142:11:142:14 | (unsigned long)... | semmle.label | (unsigned long)... | -| test.cpp:142:11:142:14 | size | semmle.label | size | -| test.cpp:142:11:142:14 | size | semmle.label | size | -| test.cpp:142:11:142:14 | size | semmle.label | size | | test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | | test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | | test.cpp:142:11:142:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:201:9:201:42 | Store | semmle.label | Store | +| test.cpp:201:14:201:19 | call to getenv | semmle.label | call to getenv | +| test.cpp:201:14:201:27 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:214:23:214:23 | s | semmle.label | s | +| test.cpp:215:21:215:21 | s | semmle.label | s | +| test.cpp:215:21:215:21 | s | semmle.label | s | +| test.cpp:215:21:215:21 | s | semmle.label | s | +| test.cpp:220:21:220:21 | s | semmle.label | s | +| test.cpp:221:21:221:21 | s | semmle.label | s | +| test.cpp:221:21:221:21 | s | semmle.label | s | +| test.cpp:221:21:221:21 | s | semmle.label | s | +| test.cpp:227:24:227:29 | call to getenv | semmle.label | call to getenv | +| test.cpp:227:24:227:37 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:229:9:229:18 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:229:9:229:18 | local_size | semmle.label | local_size | +| test.cpp:229:9:229:18 | local_size | semmle.label | local_size | +| test.cpp:229:9:229:18 | local_size | semmle.label | local_size | +| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | +| test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | +| 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) | -| test.cpp:43:38:43:63 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:48:25:48:30 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:49:17:49:30 | new[] | test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:52:21:52:27 | call to realloc | test.cpp:39:21:39:24 | argv | test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:52:35:52:60 | ... * ... | test.cpp:39:21:39:24 | argv | test.cpp:52:54:52:60 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:127:17:127:22 | call to malloc | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:41 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) | -| test.cpp:127:24:127:41 | ... * ... | test.cpp:123:18:123:23 | call to getenv | test.cpp:127:24:127:27 | size | This allocation size is derived from $@ and might overflow | test.cpp:123:18:123:23 | call to getenv | user input (getenv) | | test.cpp:134:3:134:8 | call to malloc | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) | -| test.cpp:134:10:134:27 | ... * ... | test.cpp:132:19:132:24 | call to getenv | test.cpp:134:10:134:13 | size | This allocation size is derived from $@ and might overflow | test.cpp:132:19:132:24 | call to getenv | user input (getenv) | | test.cpp:142:4:142:9 | call to malloc | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) | -| test.cpp:142:11:142:28 | ... * ... | test.cpp:138:19:138:24 | call to getenv | test.cpp:142:11:142:14 | size | This allocation size is derived from $@ and might overflow | test.cpp:138:19:138:24 | call to getenv | user input (getenv) | +| test.cpp:215:14:215:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:215:21:215: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: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 4a1bbd8a9dc..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 @@ -5,8 +5,8 @@ typedef struct {} FILE; void *malloc(size_t size); void *realloc(void *ptr, size_t size); +void free(void *ptr); int atoi(const char *nptr); - struct MyStruct { char data[256]; @@ -190,3 +190,127 @@ void more_bounded_tests() { } } } + +size_t get_untainted_size() +{ + return 10 * sizeof(int); +} + +size_t get_tainted_size() +{ + return atoi(getenv("USER")) * sizeof(int); +} + +size_t get_bounded_size() +{ + size_t s = atoi(getenv("USER")) * sizeof(int); + + if (s < 0) { s = 0; } + if (s > 100) { s = 100; } + + return s; +} + +void *my_alloc(size_t s) { + void *ptr = malloc(s); // [UNHELPFUL RESULT] + + return ptr; +} + +void my_func(size_t s) { + void *ptr = malloc(s); // BAD + + free(ptr); +} + +void more_cases() { + int local_size = atoi(getenv("USER")) * sizeof(int); + + malloc(local_size); // BAD + malloc(get_untainted_size()); // GOOD + malloc(get_tainted_size()); // BAD + malloc(get_bounded_size()); // GOOD + + my_alloc(100); // GOOD + my_alloc(local_size); // BAD [NOT DETECTED IN CORRECT LOCATION] + 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-190/semmle/wider_type/ComparisonWithWiderType.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.expected deleted file mode 100644 index 8927a6bbfc6..00000000000 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/ComparisonWithWiderType.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:4:14:4:18 | ... < ... | Comparison between $@ of type char and $@ of wider type int. | test.c:3:7:3:7 | c | c | test.c:2:17:2:17 | x | x | -| test.c:9:14:9:18 | ... > ... | Comparison between $@ of type char and $@ of wider type int. | test.c:8:7:8:7 | c | c | test.c:7:17:7:17 | x | x | -| test.c:14:14:14:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:13:8:13:8 | s | s | test.c:12:17:12:17 | x | x | -| test.c:65:14:65:18 | ... < ... | Comparison between $@ of type short and $@ of wider type int. | test.c:64:8:64:8 | s | s | test.c:63:17:63:17 | x | x | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test.c deleted file mode 100644 index 5802ca3eb4f..00000000000 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/wider_type/test.c +++ /dev/null @@ -1,78 +0,0 @@ - -void test1 (int x) { - char c; - for (c = 0; c < x; c++) {} //BAD -} - -void test2 (int x) { - char c; - for (c = 0; x > c; c++) {} // BAD -} - -void test3 (int x) { - short s; - for (s = 0; s < x; s++) {} //BAD -} - -void runner() { // get range analysis to give large values to x in tests - test1(65536); - test2(65536); - test3(655360); - test7((unsigned long long)1<<48); - test8(65536); - test9(65536); - test10(65536); - -} - -void test4 () { - short s1; - short s2 = 200; - for (s1 = 0; s1 < s2; s1++) {} -} - -void test5 () { - short s1; - int x = 65536; - s1 < x; -} - -void test6() { - short s1; - for (s1 = 0; s1 < 0x0000ffff; s1++) {} -} - -void test7(long long l) { - int i; - for (i = 0; i < l; i++) {} -} - -void test8(int x) { - short s; - for (s = 256; s < x; x--) {} -} - - -void test9(int x) { - short s; - for (s = 256; s < x; ) { - x--; - } -} - -void test10(int x) { - short s; - for (s = 0; s < x; ) { // BAD - do - { - s++; - } while (0); - } -} - -extern const int const256; - -void test11() { - short s; - for(s = 0; s < const256; ++s) {} -} \ No newline at end of file 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/ql/test/query-tests/Security/CWE/CWE-468/semmle/SuspiciousAddWithSizeof/SuspiciousAddWithSizeof.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-468/semmle/SuspiciousAddWithSizeof/SuspiciousAddWithSizeof.expected index a49ae2f59f5..8b67b3f8bc9 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-468/semmle/SuspiciousAddWithSizeof/SuspiciousAddWithSizeof.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-468/semmle/SuspiciousAddWithSizeof/SuspiciousAddWithSizeof.expected @@ -1,7 +1,7 @@ -| test.cpp:6:30:6:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:14:30:14:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:22:25:22:35 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:30:25:30:35 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:38:30:38:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:61:27:61:37 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is int *. | -| test.cpp:89:43:89:55 | sizeof(MyABC) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is myInt *const. | +| test.cpp:6:30:6:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:14:30:14:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:22:25:22:35 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:30:25:30:35 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:38:30:38:40 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:61:27:61:37 | sizeof(int) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | int * | int * | +| test.cpp:89:43:89:55 | sizeof(MyABC) | Suspicious sizeof offset in a pointer arithmetic expression. The type of the pointer is $@. | file://:0:0:0:0 | myInt *const | myInt *const | 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/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/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/old.dbscheme b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/old.dbscheme new file mode 100644 index 00000000000..d6ca4ebb768 --- /dev/null +++ b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/old.dbscheme @@ -0,0 +1,2038 @@ + +/** + * 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 + ; +*/ +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/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/semmlecode.cpp.dbscheme b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..874439f4c50 --- /dev/null +++ b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/semmlecode.cpp.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/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/upgrade.properties b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/upgrade.properties new file mode 100644 index 00000000000..62cf1ae106c --- /dev/null +++ b/cpp/upgrades/d6ca4ebb7680e241b647e78b96999eaf9d84e5b7/upgrade.properties @@ -0,0 +1,2 @@ +description: Add support for char8_t C++ builtin type +compatibility: backwards diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index b66fa4ff399..93b49891225 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -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); @@ -90,16 +90,16 @@ namespace Semmle.Extraction.Tests 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() { @@ -334,10 +334,10 @@ namespace Semmle.Extraction.Tests } 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, + 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"; @@ -462,7 +462,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap 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^"" && 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.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; @@ -733,9 +733,9 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap public void TestWindowCSharpMsBuild() { Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test2.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; @@ -764,9 +764,9 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap public void TestWindowCSharpMsBuildMultipleSolutions() { Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore test1.csproj"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild test1.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore test2.csproj"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild test2.csproj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; @@ -811,7 +811,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap public void TestWindowCSharpMsBuildFailed() { Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test1.sln"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 1; Actions.FileExists["csharp.log"] = true; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = false; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = false; @@ -837,8 +837,8 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap [Fact] public void TestSkipNugetMsBuild() { - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test1.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild C:\\Project\\test2.sln /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; @@ -1031,7 +1031,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap public void TestDirsProjWindows() { Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore dirs.proj"] = 1; - Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && C:\\odasa\\tools\\odasa index --auto msbuild dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; + Actions.RunProcess["cmd.exe /C CALL ^\"C:\\Program Files ^(x86^)\\Microsoft Visual Studio 12.0\\VC\\vcvarsall.bat^\" && set Platform=&& type NUL && C:\\odasa\\tools\\odasa index --auto msbuild dirs.proj /p:UseSharedCompilation=false /t:Windows /p:Platform=\"x86\" /p:Configuration=\"Debug\" /p:MvcBuildViews=true /P:Fu=Bar"] = 0; Actions.RunProcess[@"cmd.exe /C C:\codeql\tools\java\bin\java -jar C:\codeql\csharp\tools\extractor-asp.jar ."] = 0; Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj index 547aaa570b4..1f0016fc9b0 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj @@ -5,6 +5,7 @@ netcoreapp3.0 false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs index f6dbdae788c..a882f5bb80c 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs @@ -118,6 +118,24 @@ namespace Semmle.Autobuild /// public IBuildActions Actions { get; } + IEnumerable? FindFiles(string extension, Func create) + { + var matchingFiles = GetExtensions(extension). + Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)). + Where(p => p.ProjectOrSolution.HasLanguage(this.Options.Language)). + ToArray(); + + if (matchingFiles.Length == 0) + return null; + + if (Options.AllSolutions) + return matchingFiles.Select(p => p.ProjectOrSolution); + + return matchingFiles. + Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot). + Select(f => f.ProjectOrSolution); + } + /// /// Find all the relevant files and picks the best /// solution file and tools. @@ -151,24 +169,6 @@ namespace Semmle.Autobuild return ret; } - IEnumerable? FindFiles(string extension, Func create) - { - var matchingFiles = GetExtensions(extension). - Select(p => (ProjectOrSolution: create(p.Item1), DistanceFromRoot: p.Item2)). - Where(p => p.ProjectOrSolution.HasLanguage(this.Options.Language)). - ToArray(); - - if (matchingFiles.Length == 0) - return null; - - if (options.AllSolutions) - return matchingFiles.Select(p => p.ProjectOrSolution); - - return matchingFiles. - Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot). - Select(f => f.ProjectOrSolution); - } - // First look for `.proj` files ret = FindFiles(".proj", f => new Project(this, f))?.ToList(); if (ret != null) diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs index 5c60f4110ba..e441030ff77 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs @@ -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/CommandBuilder.cs b/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs index 444865400f4..353f132c6ec 100644 --- a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text; @@ -169,7 +169,7 @@ namespace Semmle.Autobuild arguments.Append(" &&"); } - public CommandBuilder RunCommand(string exe, string? argumentsOpt = null) + public CommandBuilder RunCommand(string exe, string? argumentsOpt = null, bool quoteExe = true) { var (exe0, arg0) = escapingMode == EscapeMode.Process && exe.EndsWith(".exe", System.StringComparison.Ordinal) @@ -183,7 +183,10 @@ namespace Semmle.Autobuild } else { - QuoteArgument(exe0); + if (quoteExe) + QuoteArgument(exe0); + else + Argument(exe0); } Argument(arg0); Argument(argumentsOpt); diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs index f9ef06feb08..569f9f183eb 100644 --- a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs @@ -57,7 +57,14 @@ namespace Semmle.Autobuild var command = new CommandBuilder(builder.Actions); if (vsTools != null) + { command.CallBatFile(vsTools.Path); + // `vcvarsall.bat` sets a default Platform environment variable, + // which may not be compatible with the supported platforms of the + // given project/solution. Unsetting it means that the default platform + // of the project/solution is used instead. + command.RunCommand("set Platform=&& type NUL", quoteExe: false); + } builder.MaybeIndex(command, MsBuild); command.QuoteArgument(projectOrSolution.FullPath); 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..6af92a0d8cb 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 + // ``` + // 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/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..bcb3b7c7a77 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql @@ -16,10 +16,10 @@ 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: // ``` // // @@ -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/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/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 65% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll rename to csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 650c15f189a..54059fb5b82 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -17,6 +17,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,8 +29,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 +37,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 +45,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 +53,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 +61,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. @@ -91,4 +82,48 @@ class CaseEdge extends EdgeKind, TCaseEdge { 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 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll similarity index 75% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll rename to csharp/ql/src/experimental/ir/implementation/IRType.qll index 833c929ecc5..dec78b413b3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -12,7 +12,9 @@ private newtype TIRType = TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or - TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or + TIRFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { + Language::hasFloatingPointType(byteSize, base, domain) + } or TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) { @@ -104,11 +106,13 @@ private class IRSizedType extends IRType { this = TIRBooleanType(byteSize) or this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) or + this = TIRFloatingPointType(byteSize, _, _) or this = TIRAddressType(byteSize) or 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. } /** @@ -126,22 +130,36 @@ 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 { IRNumericType() { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) + 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) + } + // 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() { @@ -156,7 +174,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { * 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() { @@ -171,14 +189,43 @@ class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { * A floating-point type. */ class IRFloatingPointType extends IRNumericType, TIRFloatingPointType { - final override string toString() { result = "float" + byteSize.toString() } + final private int base; + final private Language::TypeDomain domain; + + IRFloatingPointType() { this = TIRFloatingPointType(_, base, domain) } + + final override string toString() { + result = getDomainPrefix() + getBaseString() + byteSize.toString() + } final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalFloatingPointType(byteSize) + result = Language::getCanonicalFloatingPointType(byteSize, base, domain) } pragma[noinline] final override int getByteSize() { result = byteSize } + + /** Gets the numeric base of the type. Can be either 2 (binary) or 10 (decimal). */ + final int getBase() { result = base } + + /** + * Gets the type domain of the type. Can be `RealDomain`, `ComplexDomain`, or `ImaginaryDomain`. + */ + final Language::TypeDomain getDomain() { result = domain } + + private string getBaseString() { + base = 2 and result = "float" + or + base = 10 and result = "decimal" + } + + private string getDomainPrefix() { + domain instanceof Language::RealDomain and result = "" + or + domain instanceof Language::ComplexDomain and result = "c" + or + domain instanceof Language::ImaginaryDomain and result = "i" + } } /** @@ -244,12 +291,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 = @@ -257,11 +316,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 = @@ -269,5 +334,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..6852a965401 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll @@ -92,11 +92,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 97% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll rename to csharp/ql/src/experimental/ir/implementation/Opcode.qll index e7a0b6f1b4f..c0b8adbe56b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -60,8 +60,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -579,22 +577,6 @@ module Opcode { 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 - } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } 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..a0c0ca67530 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll @@ -0,0 +1,16 @@ +/** + * 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 { + 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/semmle/code/csharp/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IR.qll 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 83% 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 49cb4dd6dc4..94ef73b2769 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { 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() ) } @@ -101,23 +105,24 @@ class IRBlock extends IRBlockBase { private predicate startsBasicBlock(Instruction instr) { not instr instanceof PhiInstruction and - ( - count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor - or - exists(Instruction predecessor | - instr = predecessor.getASuccessor() and - strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 - ) // Predecessor has multiple successors - or - exists(Instruction predecessor, EdgeKind kind | - instr = predecessor.getSuccessor(kind) and - not kind instanceof GotoEdge - ) // Incoming edge is not a GotoEdge - or - exists(Instruction predecessor | - instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) - ) // A back edge enters this instruction - ) + not adjacentInBlock(_, instr) +} + +/** Holds if `i2` follows `i1` in a `IRBlock`. */ +private predicate adjacentInBlock(Instruction i1, Instruction i2) { + // - i2 must be the only successor of i1 + i2 = unique(Instruction i | i = i1.getASuccessor()) and + // - i1 must be the only predecessor of i2 + i1 = unique(Instruction i | i.getASuccessor() = i2) and + // - The edge between the two must be a GotoEdge. We just check that one + // exists since we've already checked that it's unique. + exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and + // - The edge must not be a back edge. This means we get the same back edges + // in the basic-block graph as we do in the raw CFG. + not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) + // This predicate could be simplified to remove one of the `unique`s if we + // were willing to rely on the CFG being well-formed and thus never having + // more than one successor to an instruction that has a `GotoEdge` out of it. } private predicate isEntryBlock(TIRBlock block) { @@ -129,12 +134,6 @@ private module Cached { cached newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - /** Holds if `i2` follows `i1` in a `IRBlock`. */ - private predicate adjacentInBlock(Instruction i1, Instruction i2) { - exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and - not startsBasicBlock(i2) - } - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ private Instruction getInstructionFromFirst(Instruction first, int index) = shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) 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..6b2d32af48c 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,12 @@ 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 +23,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 86% 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..a01bd2dc79a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -217,10 +217,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 } } /** @@ -265,3 +278,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/raw/Instruction.qll similarity index 95% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 38216872f2b..409577d3e46 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation 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) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -190,17 +196,18 @@ class Instruction extends Construction::TInstruction { final Language::Location getLocation() { result = getAST().getLocation() } /** - * Gets the `Expr` whose result is computed by this instruction, if any. + * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a + * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** - * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + * 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) } final Language::LanguageType getResultLanguageType() { @@ -211,6 +218,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() } /** @@ -249,7 +257,7 @@ class Instruction extends Construction::TInstruction { * 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 @@ -258,7 +266,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. @@ -319,8 +327,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: * ``` @@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -410,7 +417,7 @@ class VariableInstruction extends 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() } @@ -420,7 +427,7 @@ class FieldInstruction extends 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() } @@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -541,6 +548,11 @@ 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 } } class CopyInstruction extends Instruction { @@ -584,9 +596,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -598,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { @@ -699,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -748,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -906,7 +923,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -1211,7 +1228,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() } @@ -1229,10 +1246,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. */ @@ -1247,12 +1260,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. * @@ -1367,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } 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 79% 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..f82704094c8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -14,16 +14,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,6 +23,57 @@ 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. */ @@ -104,7 +147,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 +222,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,18 +257,15 @@ 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() } @@ -226,8 +276,15 @@ class NonPhiOperand extends Operand { /** * 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,13 +292,25 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +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 + } } class TypedOperand extends NonPhiMemoryOperand { @@ -258,8 +327,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +335,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +343,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +350,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +357,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +364,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +371,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +378,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 +385,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +402,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +409,27 @@ 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() } } 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 +459,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 +468,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/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll 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 97% 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..7171cb66c2c 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 @@ -117,6 +117,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..2901662e404 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 @@ -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..67def2600ca 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 @@ -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/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll 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 83% 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 49cb4dd6dc4..94ef73b2769 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { 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() ) } @@ -101,23 +105,24 @@ class IRBlock extends IRBlockBase { private predicate startsBasicBlock(Instruction instr) { not instr instanceof PhiInstruction and - ( - count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor - or - exists(Instruction predecessor | - instr = predecessor.getASuccessor() and - strictcount(Instruction other | other = predecessor.getASuccessor()) > 1 - ) // Predecessor has multiple successors - or - exists(Instruction predecessor, EdgeKind kind | - instr = predecessor.getSuccessor(kind) and - not kind instanceof GotoEdge - ) // Incoming edge is not a GotoEdge - or - exists(Instruction predecessor | - instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _) - ) // A back edge enters this instruction - ) + not adjacentInBlock(_, instr) +} + +/** Holds if `i2` follows `i1` in a `IRBlock`. */ +private predicate adjacentInBlock(Instruction i1, Instruction i2) { + // - i2 must be the only successor of i1 + i2 = unique(Instruction i | i = i1.getASuccessor()) and + // - i1 must be the only predecessor of i2 + i1 = unique(Instruction i | i.getASuccessor() = i2) and + // - The edge between the two must be a GotoEdge. We just check that one + // exists since we've already checked that it's unique. + exists(GotoEdge edgeKind | exists(i1.getSuccessor(edgeKind))) and + // - The edge must not be a back edge. This means we get the same back edges + // in the basic-block graph as we do in the raw CFG. + not exists(Construction::getInstructionBackEdgeSuccessor(i1, _)) + // This predicate could be simplified to remove one of the `unique`s if we + // were willing to rely on the CFG being well-formed and thus never having + // more than one successor to an instruction that has a `GotoEdge` out of it. } private predicate isEntryBlock(TIRBlock block) { @@ -129,12 +134,6 @@ private module Cached { cached newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) } - /** Holds if `i2` follows `i1` in a `IRBlock`. */ - private predicate adjacentInBlock(Instruction i1, Instruction i2) { - exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and - not startsBasicBlock(i2) - } - /** Holds if `i` is the `index`th instruction the block starting with `first`. */ private Instruction getInstructionFromFirst(Instruction first, int index) = shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index) 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..6b2d32af48c 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,12 @@ 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 +23,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 86% 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..a01bd2dc79a 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 @@ -217,10 +217,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 } } /** @@ -265,3 +278,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/unaliased_ssa/Instruction.qll similarity index 95% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 38216872f2b..409577d3e46 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation 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) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -190,17 +196,18 @@ class Instruction extends Construction::TInstruction { final Language::Location getLocation() { result = getAST().getLocation() } /** - * Gets the `Expr` whose result is computed by this instruction, if any. + * Gets the `Expr` whose result is computed by this instruction, if any. The `Expr` may be a + * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** - * Gets the unconverted `Expr` whose result is computed by this instruction, if any. + * 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) } final Language::LanguageType getResultLanguageType() { @@ -211,6 +218,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() } /** @@ -249,7 +257,7 @@ class Instruction extends Construction::TInstruction { * 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 @@ -258,7 +266,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. @@ -319,8 +327,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: * ``` @@ -395,7 +402,7 @@ class Instruction extends Construction::TInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -410,7 +417,7 @@ class VariableInstruction extends 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() } @@ -420,7 +427,7 @@ class FieldInstruction extends 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() } @@ -430,7 +437,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -440,7 +447,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -541,6 +548,11 @@ 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 } } class CopyInstruction extends Instruction { @@ -584,9 +596,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -598,11 +610,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { @@ -699,7 +716,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -748,7 +765,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -906,7 +923,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** @@ -1211,7 +1228,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() } @@ -1229,10 +1246,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. */ @@ -1247,12 +1260,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. * @@ -1367,7 +1374,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } 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 79% 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..f82704094c8 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 @@ -14,16 +14,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,6 +23,57 @@ 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. */ @@ -104,7 +147,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 +222,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,18 +257,15 @@ 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() } @@ -226,8 +276,15 @@ class NonPhiOperand extends Operand { /** * 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,13 +292,25 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +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 + } } class TypedOperand extends NonPhiMemoryOperand { @@ -258,8 +327,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -268,8 +335,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -278,8 +343,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -287,8 +350,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -296,8 +357,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -305,8 +364,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -314,8 +371,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -323,18 +378,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 +385,6 @@ class UnmodeledUseOperand extends NonPhiMemoryOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -361,8 +402,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -370,34 +409,27 @@ 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() } } 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 +459,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 +468,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/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll 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 98% 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..1612e0065b7 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 @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and @@ -247,6 +247,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 92% 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..4132bd5cd44 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 { /** 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 98% 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 index dc02760c7c4..72bb239c153 100644 --- 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 @@ -6,11 +6,12 @@ private import DebugSSA bindingset[offset] private string getKeySuffixForOffset(int offset) { + offset >= 0 and if offset % 2 = 0 then result = "" else result = "_Chi" } bindingset[offset] -private int getIndexForOffset(int offset) { result = offset / 2 } +private int getIndexForOffset(int offset) { offset >= 0 and result = offset / 2 } /** * Property provide that dumps the memory access of each result. Useful for debugging SSA 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 94% rename from csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll rename to csharp/ql/src/experimental/ir/internal/CSharpType.qll index cffe3d09f39..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) { @@ -61,9 +61,13 @@ predicate hasUnsignedIntegerType(int byteSize) { } /** - * Holds if an `IRFloatingPointType` with the specified `byteSize` should exist. + * Holds if an `IRFloatingPointType` with the specified size, base, and type domain should exist. */ -predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() } +predicate hasFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { + byteSize = any(FloatingPointType type).getSize() and + base = 2 and + domain instanceof Language::RealDomain +} private predicate isPointerIshType(Type type) { type instanceof PointerType or @@ -314,9 +318,11 @@ CSharpPRValueType getCanonicalUnsignedIntegerType(int byteSize) { /** * Gets the `CSharpType` that is the canonical type for an `IRFloatingPointType` with the specified - * `byteSize`. + * size, base, and type domain. */ -CSharpPRValueType getCanonicalFloatingPointType(int byteSize) { +CSharpPRValueType getCanonicalFloatingPointType(int byteSize, int base, Language::TypeDomain domain) { + base = 2 and + domain instanceof Language::RealDomain and result = TPRValueType(any(FloatingPointType type | type.getSize() = byteSize)) } @@ -362,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 76% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll rename to csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll index a8fb448f8d0..2272257fb19 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll @@ -28,6 +28,44 @@ class IntegralType = CSharp::IntegralType; class FloatingPointType = CSharp::FloatingPointType; +private newtype TTypeDomain = TRealDomain() + +/** + * The type domain of a floating-point type. One of `RealDomain`, `ComplexDomain`, or + * `ImaginaryDomain`. + */ +class TypeDomain extends TTypeDomain { + /** Gets a textual representation of this type domain. */ + string toString() { none() } +} + +/** + * The type domain of a floating-point type that represents a real number. + */ +class RealDomain extends TypeDomain, TRealDomain { + final override string toString() { result = "real" } +} + +/** + * The type domain of a floating-point type that represents a complex number. Not currently used in + * C#. + */ +class ComplexDomain extends TypeDomain { + ComplexDomain() { none() } + + final override string toString() { result = "complex" } +} + +/** + * The type domain of a floating-point type that represents an imaginary number. Not currently used + * in C#. + */ +class ImaginaryDomain extends TypeDomain { + ImaginaryDomain() { none() } + + final override string toString() { result = "imaginary" } +} + private newtype TClassDerivation = // Note that this is the `Class` type exported from this module, not CSharp::Class. MkClassDerivation(Class base, Class derived) { derived.getABaseType() = base } 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..228b5a29b3c 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`. 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..543d58355db 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll @@ -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/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index e9e8f44c818..4443ec9bc7c 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -68,6 +68,8 @@ module Stages { or exists(any(DataFlow::Node n).getType()) or + exists(any(DataFlow::Node n).getTypeBound()) + or exists(any(DataFlow::Node n).getLocation()) or exists(any(DataFlow::Node n).toString()) diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index f3ef15d59f7..2ed9e5cf03a 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() } /** diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 79481a8c63d..5aec92ebb98 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() @@ -199,24 +197,6 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { * ``` */ 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)) } @@ -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() { diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index 6e523e1ea30..1007ed2aaf9 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -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/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 710a4ac8f95..6b64abe88aa 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -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 (...) {...}" } /** @@ -310,73 +307,6 @@ 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 @@ -1160,26 +1090,6 @@ class UsingStmt extends Stmt, @using_stmt { * ``` */ 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() } } /** @@ -1212,7 +1122,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * } * ``` */ - 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 (...) {...}" } } diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index 3cd6ef14d41..fef53c08641 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -769,12 +769,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() } } /** 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/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/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 8a6fdafc903..fdf6f986554 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -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) } } @@ -553,7 +553,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 + // ``` + // 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. */ @@ -1710,9 +1720,9 @@ module ControlFlow { exists(getAThrownException(ts, cfe, c)) and result = first(ts.getCatchClause(0)) or - exists(SpecificCatchClause scc, int i | scc = ts.getCatchClause(i) | - cfe = scc and - scc = last(ts.getCatchClause(i), c) and + exists(CatchClause cc, int i | cc = ts.getCatchClause(i) | + cfe = cc and + cc = last(ts.getCatchClause(i), c) and ( // Flow from one `catch` clause to the next result = first(ts.getCatchClause(i + 1)) and @@ -1725,7 +1735,7 @@ module ControlFlow { ) or cfe = last(ts.getCatchClause(i), c) and - cfe = last(scc.getFilterClause(), _) and + cfe = last(cc.getFilterClause(), _) and ( // Flow from last element of `catch` clause filter to next `catch` clause result = first(ts.getCatchClause(i + 1)) and @@ -1739,7 +1749,7 @@ module ControlFlow { ) or // Flow from last element of a `catch` block to first element of `finally` block - cfe = lastCatchClauseBlock(scc, c) and + cfe = lastCatchClauseBlock(cc, c) and result = first(ts.getFinally()) ) or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 87eee2a80be..1f08f81548a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -16,113 +16,49 @@ 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.DataFlowPublic +private import semmle.code.csharp.dataflow.internal.DelegateDataFlow -cached -private module Cached { - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to `sink` using a call to a library - * callable. - */ - cached - predicate libraryFlow(Expr source, Expr sink, boolean preservesValue) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSink csink, Call c | - source = csource.getSource(c) and - ltdf.callableFlow(csource, csink, c.getTarget().getSourceDeclaration(), preservesValue) and - sink = csink.getSink(c) - ) - } +private newtype TAccessPath = + TNilAccessPath() or + TAccessPathConsNil(Content c) - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to the `out`/`ref` argument `outRef` using a call to a library - * callable. - */ - cached - predicate libraryFlowOutRef(MethodCall mc, Expr source, Parameter outRef, boolean preservesValue) { - exists( - LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSinkArg csink, Method sm - | - source = csource.getSource(mc) and - mc.getTarget().getAParameter() = outRef and - sm = mc.getTarget().getSourceDeclaration() and - ltdf.callableFlow(csource, csink, sm, preservesValue) and - csink = getFlowSinkArg(sm, outRef.getPosition()) - ) - } +/** An access path of length 0 or 1. */ +class AccessPath extends TAccessPath { + /** Gets the head of this access path, if any. */ + Content getHead() { this = TAccessPathConsNil(result) } - /** - * INTERNAL: Do not use. - * - * Holds if output from the `i`th delegate argument of `call` can flow to `sink`, using - * the library target `callable`. - */ - cached - predicate libraryFlowDelegateCallOut( - Call call, Callable callable, Expr sink, boolean preservesValue, int i - ) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSourceDelegateArg csource, CallableFlowSink csink | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csource = getDelegateFlowSourceArg(callable, i) and - sink = csink.getSink(call) - ) - } + /** Holds if this access path contains content `c`. */ + predicate contains(Content c) { this = TAccessPathConsNil(c) } - /** - * INTERNAL: Do not use. - * - * Holds if `source` can flow to the `i`th parameter of the delegate at argument - * `j`. The call `call` is the call in which `sink` is an argument and`callable` - * is the library target. - */ - cached - predicate libraryFlowDelegateCallIn( - Call call, Callable callable, Expr source, boolean preservesValue, int i, int j - ) { - exists(LibraryTypeDataFlow ltdf, CallableFlowSource csource, CallableFlowSinkDelegateArg csink | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csink = getDelegateFlowSinkArg(callable, j, i) and - source = csource.getSource(call) - ) - } - - /** - * INTERNAL: Do not use. - * - * Holds if output from the `i`th delegate argument of `call` can flow to the `j`th parameter - * of the of delegate at argument `k`, using the library target `callable`. - */ - cached - predicate libraryFlowDelegateCallOutIn( - Call call, Callable callable, boolean preservesValue, int i, int j, int k - ) { - exists( - LibraryTypeDataFlow ltdf, CallableFlowSourceDelegateArg csource, - CallableFlowSinkDelegateArg csink - | - ltdf.callableFlow(csource, csink, callable, preservesValue) and - call.getTarget().getSourceDeclaration() = callable and - csource = getDelegateFlowSourceArg(callable, i) and - csink = getDelegateFlowSinkArg(callable, k, j) - ) + /** Gets a textual representation of this access path. */ + string toString() { + result = this.getHead().toString() + or + this = TNilAccessPath() and + result = "" } } -import Cached +/** Provides predicates for constructing access paths. */ +module AccessPath { + /** Gets the empty access path. */ + AccessPath empty() { result = TNilAccessPath() } + + /** Gets a singleton property access path. */ + AccessPath property(Property p) { + result = TAccessPathConsNil(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) + } +} /** An unbound callable. */ -library class SourceDeclarationCallable extends Callable { - SourceDeclarationCallable() { this = getSourceDeclaration() } +class SourceDeclarationCallable extends Callable { + SourceDeclarationCallable() { this = this.getSourceDeclaration() } } /** An unbound method. */ -library class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } +class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } -// Internal representation of callable flow sources private newtype TCallableFlowSource = TCallableFlowSourceQualifier() or TCallableFlowSourceArg(int i) { hasArgumentPosition(_, i) } or @@ -160,83 +96,119 @@ private predicate hasDelegateArgumentPosition2(SourceDeclarationCallable c, int ) } -/** A flow source in a call to a library callable. */ +/** A flow source specification. */ class CallableFlowSource extends TCallableFlowSource { - /** Gets a textual representation of this flow source. */ + /** Gets a textual representation of this flow source specification. */ string toString() { none() } /** Gets the source of flow for call `c`, if any. */ Expr getSource(Call c) { none() } + + /** + * Gets the type of the source for call `c`. Unlike `getSource()`, this + * is defined for all flow source specifications. + */ + Type getSourceType(Call c) { result = this.getSource(c).getType() } } -/** A flow source in a call to a library callable: qualifier. */ +/** A flow source specification: (method call) qualifier. */ class CallableFlowSourceQualifier extends CallableFlowSource, TCallableFlowSourceQualifier { override string toString() { result = "qualifier" } override Expr getSource(Call c) { result = c.getChild(-1) } } -/** A flow source in a call to a library callable: argument. */ +/** A flow source specification: (method call) argument. */ class CallableFlowSourceArg extends CallableFlowSource, TCallableFlowSourceArg { - override string toString() { result = "argument " + this.getArgumentIndex() } + private int i; + + CallableFlowSourceArg() { this = TCallableFlowSourceArg(i) } /** Gets the index of this argument. */ - int getArgumentIndex() { this = TCallableFlowSourceArg(result) } + int getArgumentIndex() { result = i } - override Expr getSource(Call c) { result = c.getArgument(getArgumentIndex()) } + override string toString() { result = "argument " + i } + + override Expr getSource(Call c) { result = c.getArgument(i) } } -/** A flow source in a call to a library callable: output from delegate argument. */ +/** A flow source specification: output from delegate argument. */ class CallableFlowSourceDelegateArg extends CallableFlowSource, TCallableFlowSourceDelegateArg { - override string toString() { result = "output from argument " + getArgumentIndex().toString() } + private int i; + + CallableFlowSourceDelegateArg() { this = TCallableFlowSourceDelegateArg(i) } /** Gets the index of this delegate argument. */ - int getArgumentIndex() { this = TCallableFlowSourceDelegateArg(result) } + int getArgumentIndex() { result = i } + + override string toString() { result = "output from argument " + i } override Expr getSource(Call c) { none() } + + override Type getSourceType(Call c) { result = c.getArgument(i).getType() } } -// Internal representation of callable flow sinks private newtype TCallableFlowSink = TCallableFlowSinkQualifier() or TCallableFlowSinkReturn() or TCallableFlowSinkArg(int i) { exists(SourceDeclarationCallable c | exists(c.getParameter(i))) } or TCallableFlowSinkDelegateArg(int i, int j) { hasDelegateArgumentPosition2(_, i, j) } -/** A flow sink in a call to a library callable. */ +/** A flow sink specification. */ class CallableFlowSink extends TCallableFlowSink { - /** Gets a textual representation of this flow sink. */ + /** Gets a textual representation of this flow sink specification. */ string toString() { none() } /** Gets the sink of flow for call `c`, if any. */ Expr getSink(Call c) { none() } + + /** + * Gets the type of the sink for call `c`. Unlike `getSink()`, this is defined + * for all flow sink specifications. + */ + Type getSinkType(Call c) { result = this.getSink(c).getType() } } -/** A flow sink in a call to a library callable: qualifier. */ +/** A flow sink specification: (method call) qualifier. */ class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier { override string toString() { result = "qualifier" } override Expr getSink(Call c) { result = c.getChild(-1) } } -/** A flow sink in a call to a library callable: return value. */ +/** A flow sink specification: return value. */ class CallableFlowSinkReturn extends CallableFlowSink, TCallableFlowSinkReturn { override string toString() { result = "return" } override Expr getSink(Call c) { result = c } } -/** The flow sink in an argument to a call to a library method. */ +/** A flow sink specification: (method call) argument. */ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { - override string toString() { result = "argument " + this.getArgumentIndex() } + private int i; + + CallableFlowSinkArg() { this = TCallableFlowSinkArg(i) } /** Gets the index of this `out`/`ref` argument. */ - int getArgumentIndex() { this = TCallableFlowSinkArg(result) } + int getArgumentIndex() { result = i } + + /** Gets the `out`/`ref` argument of method call `mc` matching this specification. */ + Expr getArgument(MethodCall mc) { + exists(Parameter p | + p = mc.getTarget().getParameter(i) and + p.isOutOrRef() and + result = mc.getArgumentForParameter(p) + ) + } + + override string toString() { result = "argument " + i } override Expr getSink(Call c) { // The uses of the `i`th argument are the actual sinks none() } + + override Type getSinkType(Call c) { result = this.getArgument(c).getType() } } /** Gets the flow source for argument `i` of callable `callable`. */ @@ -245,12 +217,6 @@ private CallableFlowSourceArg getFlowSourceArg(SourceDeclarationCallable callabl hasArgumentPosition(callable, i) } -/** Gets the flow sink for argument `i` of callable `callable`. */ -private CallableFlowSinkArg getFlowSinkArg(SourceDeclarationCallable callable, int i) { - i = result.getArgumentIndex() and - hasArgumentPosition(callable, i) -} - /** Gets the flow source for argument `i` of delegate `callable`. */ private CallableFlowSourceDelegateArg getDelegateFlowSourceArg( SourceDeclarationCallable callable, int i @@ -267,11 +233,23 @@ private CallableFlowSinkDelegateArg getDelegateFlowSinkArg( hasDelegateArgumentPosition2(callable, i, j) } -/** The flow sink in a call to a library callable: parameter of a delegate argument. */ +/** A flow sink specification: parameter of a delegate argument. */ class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDelegateArg { + private int delegateIndex; + private int parameterIndex; + + CallableFlowSinkDelegateArg() { + this = TCallableFlowSinkDelegateArg(delegateIndex, parameterIndex) + } + + /** Gets the index of the delegate argument. */ + int getDelegateIndex() { result = delegateIndex } + + /** Gets the index of the delegate parameter. */ + int getDelegateParameterIndex() { result = parameterIndex } + override string toString() { - result = - "parameter " + getDelegateParameterIndex() + " of argument " + getDelegateIndex().toString() + result = "parameter " + parameterIndex + " of argument " + delegateIndex } override Expr getSink(Call c) { @@ -279,18 +257,20 @@ class CallableFlowSinkDelegateArg extends CallableFlowSink, TCallableFlowSinkDel none() } - /** Gets the index of the delegate argument. */ - int getDelegateIndex() { this = TCallableFlowSinkDelegateArg(result, _) } - - /** Gets the index of the delegate parameter. */ - int getDelegateParameterIndex() { this = TCallableFlowSinkDelegateArg(_, result) } + override Type getSinkType(Call c) { + result = + c + .getArgument(delegateIndex) + .(DelegateArgumentToLibraryCallable) + .getDelegateType() + .getParameter(parameterIndex) + .getType() + } } -/** - * A specification of data flow for a library (non-source code) type. - */ +/** A specification of data flow for a library (non-source code) type. */ abstract class LibraryTypeDataFlow extends Type { - LibraryTypeDataFlow() { this = getSourceDeclaration() } + LibraryTypeDataFlow() { this = this.getSourceDeclaration() } /** * Holds if data may flow from `source` to `sink` when calling callable `c`. @@ -300,10 +280,27 @@ abstract class LibraryTypeDataFlow extends Type { * to `x.ToString()` when `x` is a `string`, but not from `x` to `x.ToLower()`. */ pragma[nomagic] - abstract predicate callableFlow( + predicate callableFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue - ); + ) { + none() + } + + /** + * Holds if data may flow from `source` to `sink` when calling callable `c`. + * + * `sourceAp` describes the contents of `source` that flows to `sink` + * (if any), and `sinkContent` describes the contents of `sink` that it + * flows to (if any). + */ + pragma[nomagic] + predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c + ) { + none() + } } /** Data flow for `System.Int32`. */ @@ -614,38 +611,20 @@ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringB } /** Data flow for `System.Lazy<>`. */ -class SystemLazyFlow extends LibraryTypeDataFlow { - SystemLazyFlow() { this instanceof SystemLazyClass } - +class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - ( - constructorFlow(source, sink, c) - or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = true - } - - private predicate constructorFlow( - CallableFlowSourceDelegateArg source, CallableFlowSink sink, Constructor c + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c ) { exists(SystemFuncDelegateType t, int i | t.getNumberOfTypeParameters() = 1 | - c.getDeclaringType() = this and + c.(Constructor).getDeclaringType() = this and c.getParameter(i).getType().getSourceDeclaration() = t and source = getDelegateFlowSourceArg(c, i) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(this.getValueProperty()) ) } - - private predicate propertyFlow(Property p) { p = this.(SystemLazyClass).getValueProperty() } } /** @@ -755,6 +734,11 @@ class IEnumerableFlow extends LibraryTypeDataFlow { sink = TCallableFlowSinkReturn() ) or + name = "AsQueryable" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sink = TCallableFlowSinkReturn() + or name = "Average" and ( arity = 2 and 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..a9e27915fe3 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. */ 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 b05595c32c3..2b09436f27d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll @@ -173,15 +173,16 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. */ + pragma[nomagic] predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | this.reachesBasicBlockExprBase(e1, e2, _, _, isSuccessor, cfn1, i, bb) and cfn2 = bb.getNode(j) and cfn2 = e2.getAControlFlowNode() | - isSuccessor = true and j > i + isSuccessor = true and j >= i or - isSuccessor = false and i > j + isSuccessor = false and i >= j ) or exists(ControlFlow::BasicBlock bb | @@ -195,6 +196,7 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. */ + pragma[nomagic] predicate hasDefPath( Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef ) { @@ -203,9 +205,9 @@ abstract class ControlFlowReachabilityConfiguration extends string { cfnDef = bb.getNode(j) and def.getAControlFlowNode() = cfnDef | - isSuccessor = true and j > i + isSuccessor = true and j >= i or - isSuccessor = false and i > j + isSuccessor = false and i >= j ) or exists(ControlFlow::BasicBlock bb | @@ -219,6 +221,7 @@ abstract class ControlFlowReachabilityConfiguration extends string { * Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an * expression node or an SSA definition node. */ + pragma[nomagic] predicate hasNodePath(ExprNode n1, Node n2) { exists(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2 | this.hasExprPath(e1, cfn1, e2, cfn2) 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 1e1353279a1..fa5c0e54f3e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -117,23 +117,52 @@ private module Cached { result = call.(DelegateDataFlowCall).getARuntimeTarget(cc) } + /** + * 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). + */ + private predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { + c = call.getEnclosingCallable() and + ( + exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | + not cc instanceof EmptyCallContext + ) + or + call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext() + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * targets of call `call` in `c`. */ cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { - c = viableImpl(ctx) and - c = call.getEnclosingCallable() and - exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | - not cc instanceof EmptyCallContext + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableImpl(call)) and + ctxtgts < tgts ) } + /** + * 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. + */ private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | cc.isArgument(ctx.getExpr(), _) ) + or + result = + call + .(NonDelegateDataFlowCall) + .getDispatchCall() + .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) } /** @@ -155,9 +184,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and c = viableImpl(call) and - ctxtgts = strictcount(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableImpl(ctx) = call.getEnclosingCallable()) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -278,6 +308,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()) } @@ -346,11 +379,14 @@ class ImplicitDelegateDataFlowCall extends DelegateDataFlowCall, TImplicitDelega /** Gets the number of parameters of the supplied delegate. */ int getNumberOfDelegateParameters() { result = arg.getDelegateType().getNumberOfParameters() } + /** Gets the type of the `i`th parameter of the supplied delegate. */ + Type getDelegateParameterType(int i) { result = arg.getDelegateType().getParameter(i).getType() } + /** Gets the return type of the supplied delegate. */ Type getDelegateReturnType() { result = arg.getDelegateType().getReturnType() } override DotNet::Callable getARuntimeTarget(CallContext::CallContext cc) { - result = cfn.getElement().(DelegateArgumentToLibraryCallable).getARuntimeTarget(cc) + result = arg.getARuntimeTarget(cc) } override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } 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 a1daeb66411..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 783ac641e6e..1f42c21d5a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,167 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output 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. */ - cached 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), and `contentOut` describes the content of `node` that - * it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) 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 - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() + 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), read.getContainerType()) ) or - // store - exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) - ) - or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, read) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through `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), and - * `contentOut` describes the content of `out` that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } /** - * 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. + * 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. */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() + 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), and `contentOut` describes the content of the return - * node that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, read) and + kind = ret.getKind() + ) } } import Final } + /** + * 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(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and + containerType = getErasedNodeTypeBound(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 = getErasedNodeTypeBound(n1) and + containerType = getErasedNodeTypeBound(n2) + ) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,17 +367,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(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), TContentNone(), 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 @@ -520,6 +409,24 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + 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(TypedContent tc) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,26 +436,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 = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) +} -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()" } } /** @@ -678,6 +597,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 @@ -688,7 +619,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 { @@ -700,7 +631,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 { @@ -712,9 +645,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()) ) } @@ -779,77 +712,79 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** 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. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + private DataFlowType t; + + 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 { + private TypedContent tc; + + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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 4a6693fbebf..0dc66f1d377 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -16,6 +16,42 @@ private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate +abstract class NodeImpl extends Node { + /** Do not call: use `getEnclosingCallable()` instead. */ + abstract DataFlowCallable getEnclosingCallableImpl(); + + /** Do not call: use `getType()` instead. */ + abstract DotNet::Type getTypeImpl(); + + /** 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 { private class BasicBlock = ControlFlow::BasicBlock; @@ -81,9 +117,6 @@ module LocalFlow { ) { exactScope = false and ( - // Flow using library code - libraryFlow(e1, e2, scope, isSuccessor, true) - or e1 = e2.(ParenthesizedExpr).getExpr() and scope = e2 and isSuccessor = true @@ -244,39 +277,9 @@ module LocalFlow { nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable()) ) } - - private Expr getALibraryFlowParentFrom(Expr exprFrom, Expr exprTo, boolean preservesValue) { - libraryFlow(exprFrom, exprTo, preservesValue) and - result = exprFrom - or - result.getAChildExpr() = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) - } - - private Expr getALibraryFlowParentTo(Expr exprFrom, Expr exprTo, boolean preservesValue) { - libraryFlow(exprFrom, exprTo, preservesValue) and - result = exprTo - or - exists(Expr mid | mid = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) | - result.getAChildExpr() = mid and - not mid = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) - ) - } - - pragma[noinline] - predicate libraryFlow( - Expr exprFrom, Expr exprTo, Expr scope, boolean isSuccessor, boolean preservesValue - ) { - // To not pollute the definitions in `LibraryTypeDataFlow.qll` with syntactic scope, - // simply use the nearest common parent expression for `exprFrom` and `exprTo` - scope = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) and - scope = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) and - // Similarly, for simplicity allow following both forwards and backwards edges from - // `exprFrom` to `exprTo` - (isSuccessor = true or isSuccessor = false) - } } -/** An argument of a C# call. */ +/** An argument of a C# call (including qualifier arguments). */ private class Argument extends Expr { private Expr call; private int arg; @@ -292,39 +295,85 @@ private class Argument extends Expr { this = call.(DelegateCall).getArgument(arg) } - /** Holds if this expression is the `i`th argument of `c`. */ + /** + * Holds if this expression is the `i`th argument of `c`. + * + * Qualifier arguments have index `-1`. + */ predicate isArgumentOf(Expr c, int i) { c = call and i = arg } } /** - * Holds if `e` is an assignment of `src` to a non-static field or field-like - * property `f` of `q`. + * Holds if `e` is an assignment of `src` to field or property `c` of `q`. */ -private predicate instanceFieldLikeAssign(Expr e, FieldLike f, Expr src, Expr q) { - exists(FieldLikeAccess fa, AssignableDefinition def | +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().getSourceDeclaration() and - not f.isStatic() and + f = fa.getTarget() and + 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()) + ) ) } /** - * Holds if `oc` has an object initializer that assigns `src` to non-static field or - * field-like property `f`. + * Holds if `oc` has an object initializer that assigns `src` to field or + * property `c`. */ -private predicate instanceFieldLikeInit(ObjectCreation oc, FieldLike f, Expr src) { - exists(MemberInitializer mi | +private predicate fieldOrPropertyInit(ObjectCreation oc, Content c, Expr src) { + exists(MemberInitializer mi, FieldOrProperty f | mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and - f = mi.getInitializedMember().getSourceDeclaration() and - not f.isStatic() and + f = mi.getInitializedMember() and + c = f.getContent() and src = mi.getRValue() + | + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + LibraryFlow::libraryFlow(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) } -private Type getCSharpType(DotNet::Type t) { +/** Holds if property `p1` overrides or implements source declaration property `p2`. */ +private predicate overridesOrImplementsSourceDecl(Property p1, Property p2) { + p1.getOverridee*().getSourceDeclaration() = p2 + or + p1.getAnUltimateImplementee().getSourceDeclaration() = p2 +} + +/** + * Holds if `e2` is an expression that reads field or property `c` from + * expresion `e1`. This takes overriding into account for properties written + * from library code. + */ +private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2) { + e1 = e2.getQualifier() and + exists(FieldOrProperty ret | c = ret.getContent() | + ret.isFieldLike() and + ret = e2.getTarget() + or + exists(AccessPath ap, Property target | + LibraryFlow::libraryFlow(_, _, _, _, ap, _) and + ap.contains(ret.getContent()) and + target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and + overridesOrImplementsSourceDecl(target, ret) + ) + ) +} + +Type getCSharpType(DotNet::Type t) { result = t or result.matchesHandle(t) @@ -359,8 +408,7 @@ private module Cached { TSsaDefinitionNode(Ssa::Definition def) or TInstanceParameterNode(Callable c) { c.hasBody() and not c.(Modifiable).isStatic() } or TCilParameterNode(CIL::Parameter p) { p.getMethod().hasBody() } or - TTaintedParameterNode(Parameter p) { explicitParameterNode(_, p) } or - TTaintedReturnNode(ControlFlow::Nodes::ElementNode cfn) { + TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) { any(Callable c).canYieldReturn(cfn.getElement()) } or TImplicitCapturedArgumentNode(ControlFlow::Nodes::ElementNode cfn, LocalScopeVariable v) { @@ -374,6 +422,14 @@ private module Cached { cfn.getElement() instanceof DelegateArgumentToLibraryCallable and any(DelegateArgumentConfiguration x).hasExprPath(_, cfn, _, call) } or + TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { + exists(Call call, CallableFlowSinkDelegateArg sink | + LibraryFlow::libraryFlow(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 TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) { exists(Argument a, Type t | @@ -386,13 +442,19 @@ private module Cached { t = any(TypeParameter tp | not tp.isValueType()) ) or - instanceFieldLikeAssign(_, _, _, cfn.getElement()) + fieldOrPropertyAssign(_, _, _, cfn.getElement()) or - exists(TExprPostUpdateNode upd, FieldLikeAccess fla | + exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla | upd = TExprPostUpdateNode(fla.getAControlFlowNode()) | cfn.getElement() = fla.getQualifier() ) + } or + TLibraryCodeNode( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue + ) { + LibraryFlow::libraryFlow(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) } /** @@ -415,11 +477,15 @@ private module Cached { or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true) - or - flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true) - or LocalFlow::localFlowStepCil(nodeFrom, nodeTo) + or + exists(LibraryCodeNode n | n.preservesValue() | + n = nodeTo and + nodeFrom = n.getPredecessor(AccessPath::empty()) + or + n = nodeFrom and + nodeTo = n.getSuccessor(AccessPath::empty()) + ) } /** @@ -446,25 +512,26 @@ private module Cached { cached newtype TContent = - TFieldLikeContent(FieldLike f) { not f.isStatic() and f.getSourceDeclaration() = f } + TFieldContent(Field f) { f = f.getSourceDeclaration() } or + TPropertyContent(Property p) { p = p.getSourceDeclaration() } /** * Holds if data can flow from `node1` to `node2` via an assignment to * content `c`. */ cached - predicate storeStepImpl(ExprNode node1, Content c, PostUpdateNode node2) { - exists(StoreStepConfiguration x, Node preNode2 | - preNode2 = node2.getPreUpdateNode() and + predicate storeStepImpl(Node node1, Content c, Node node2) { + exists(StoreStepConfiguration x, ExprNode preNode2 | + preNode2 = node2.(PostUpdateNode).getPreUpdateNode() and x.hasNodePath(node1, preNode2) and - instanceFieldLikeAssign(_, c.(FieldLikeContent).getField(), node1.asExpr(), preNode2.asExpr()) + fieldOrPropertyAssign(_, c, node1.asExpr(), preNode2.getExpr()) ) or - exists(StoreStepConfiguration x | - x.hasNodePath(node1, node2) and - instanceFieldLikeInit(node2.(ObjectCreationNode).getExpr(), c.(FieldLikeContent).getField(), - node1.asExpr()) + exists(StoreStepConfiguration x | x.hasNodePath(node1, node2) | + fieldOrPropertyInit(node2.(ObjectCreationNode).getExpr(), c, node1.asExpr()) ) + or + node2 = node1.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c)) } /** @@ -474,9 +541,10 @@ private module Cached { predicate readStepImpl(Node node1, Content c, Node node2) { exists(ReadStepConfiguration x | x.hasNodePath(node1, node2) and - c.(FieldLikeContent).getField() = - node2.asExpr().(FieldLikeRead).getTarget().getSourceDeclaration() + fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) ) + or + node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) } /** @@ -495,19 +563,6 @@ private module Cached { ) } - /** - * Gets a representative type for `t` for the purpose of pruning possible flow. - */ - cached - DataFlowType getErasedRepr(DotNet::Type t) { - exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | - t0 = getCSharpType(t) - or - not exists(getCSharpType(t)) and - t0 instanceof ObjectType - ) - } - /** * Holds if GVNs `t1` and `t2` may have a common sub type. Neither `t1` nor * `t2` are allowed to be type parameters. @@ -534,7 +589,7 @@ private module Cached { 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) } @@ -542,19 +597,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`. */ @@ -566,7 +625,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() { @@ -578,17 +637,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) } @@ -598,51 +659,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() } - /** - * A tainted parameter. Tainted parameters are a mere implementation detail, used - * to restrict tainted flow into callables to just taint tracking (just like flow - * out of `TaintedReturnNode`s is restricted to taint tracking). - */ - class TaintedParameterNode extends ParameterNode, TTaintedParameterNode { - private Parameter parameter; - - TaintedParameterNode() { this = TTaintedParameterNode(parameter) } - - /** Gets the underlying parameter node. */ - ExplicitParameterNode getUnderlyingNode() { explicitParameterNode(result, parameter) } - - // `getParameter()` is explicitly *not* overriden to return `parameter`, - // as that would otherwise enable tainted parameters to accidentally be - // used by users of the library - override predicate isParameterOf(DataFlowCallable c, int i) { - c = parameter.getCallable() and - // we model tainted parameters as if they had been extra parameters after - // the actual parameters - i = parameter.getPosition() + c.getNumberOfParameters() - } - - override Callable getEnclosingCallable() { - result = this.getUnderlyingNode().getEnclosingCallable() - } - - override Type getType() { - // Taint tracking steps are allowed to change the type of the tracked object, - // so `result = this.getUnderlyingNode().getType()` is too restrictive - result instanceof ObjectType - } - - override Location getLocation() { result = this.getUnderlyingNode().getLocation() } - - override string toString() { result = this.getUnderlyingNode().toString() } + override string toStringImpl() { result = "this" } } module ImplicitCapturedParameterNodeImpl { @@ -688,7 +713,7 @@ private module ParameterNodes { * An implicit parameter is added in order to be able to track flow into * capturing callables, as if an explicit `ref` parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void In() { => void In(ref int i0) { // implicit i0 parameter @@ -741,47 +766,6 @@ private module ArgumentNodes { } } - /** - * Holds if `arg` is an argument of a call, which resolves to a library callable - * that is known to forward `arg` into the `i`th parameter of a supplied - * delegate `delegate`. - * - * For example, in - * - * ``` - * x.Select(Foo); - * ``` - * - * `arg = x`, `i = 0`, `call = x.Select(Foo)`, and `delegate = Foo`. - */ - private predicate flowIntoCallableLibraryCall( - ExplicitArgumentNode arg, ImplicitDelegateDataFlowCall delegate, int i - ) { - exists(DataFlowCall call, int j, boolean preservesValue | - preservesValue = true and i = j - or - preservesValue = false and i = j + delegate.getNumberOfDelegateParameters() - | - exists(DelegateArgumentConfiguration x, Call callExpr, ExprNode argExpr | - x - .hasExprPath(argExpr.getExpr(), argExpr.getControlFlowNode(), callExpr, - call.getControlFlowNode()) - | - exists(int k | - libraryFlowDelegateCallIn(callExpr, _, argExpr.getExpr(), preservesValue, j, k) and - arg = argExpr and - delegate.isArgumentOf(call, k) - ) - or - exists(int k, int l | libraryFlowDelegateCallOutIn(callExpr, _, preservesValue, k, j, l) | - delegate.isArgumentOf(call, l) and - arg.(ImplicitDelegateOutNode).isArgumentOf(call, k) and - arg = TImplicitDelegateOutNode(argExpr.getControlFlowNode(), _) - ) - ) - ) - } - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { ArgumentConfiguration() { this = "ArgumentConfiguration" } @@ -801,10 +785,6 @@ private module ArgumentNodes { this.asExpr() instanceof Argument or this.asExpr() = any(CIL::Call call).getAnArgument() - or - libraryFlowDelegateCallIn(_, _, this.asExpr(), _, _, _) - or - this.(ImplicitDelegateOutNode).isArgumentOf(_, _) } override predicate argumentOf(DataFlowCall call, int pos) { @@ -821,8 +801,6 @@ private module ArgumentNodes { c = call.getExpr() and arg = c.getArgument(pos) ) - or - flowIntoCallableLibraryCall(this, call, pos) } } @@ -833,7 +811,7 @@ private module ArgumentNodes { * An implicit node is added in order to be able to track flow into capturing * callables, as if an explicit parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void Out() { i = 1; } => void Out(ref int i0) { i0 = 1; } @@ -842,7 +820,7 @@ private module ArgumentNodes { * } } * ``` */ - class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode { + class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode { private LocalScopeVariable v; private ControlFlow::Nodes::ElementNode cfn; @@ -880,20 +858,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) } @@ -903,15 +883,54 @@ 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" } + } + + /** + * A data flow node that represents an implicit argument of an implicit delegate + * call in library code. For example, in + * + * ```csharp + * x.Select(Foo); + * ``` + * + * `x` is an implicit argument of the implicit call to `Foo`. + */ + class ImplicitDelegateArgumentNode extends ArgumentNode, NodeImpl, TImplicitDelegateArgumentNode { + private ControlFlow::Node cfn; + private int delegateIndex; + private int parameterIndex; + + ImplicitDelegateArgumentNode() { + this = TImplicitDelegateArgumentNode(cfn, delegateIndex, parameterIndex) + } + + private ImplicitDelegateDataFlowCall getDelegateCall() { result.getControlFlowNode() = cfn } + + override predicate argumentOf(DataFlowCall call, int pos) { + call = this.getDelegateCall() and + pos = parameterIndex + } + + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + + override Type getTypeImpl() { + result = this.getDelegateCall().getDelegateParameterType(parameterIndex) + } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn } } } @@ -964,31 +983,29 @@ private module ReturnNodes { } /** - * A tainted return node. Tainted return nodes are a mere implementation detail, - * used to restrict tainted flow out of callables to just taint tracking (just - * like flow in to `TaintedReturnParameter`s is restricted to taint tracking). + * A `yield return` node. A node is synthesized in order to be able to model + * `yield return`s as stores into collections, i.e., there is flow from `e` + * to `yield return e [e]`. */ - class TaintedReturnNode extends ReturnNode, TTaintedReturnNode { + class YieldReturnNode extends ReturnNode, NodeImpl, TYieldReturnNode { private ControlFlow::Nodes::ElementNode cfn; + private YieldReturnStmt yrs; - TaintedReturnNode() { this = TTaintedReturnNode(cfn) } + YieldReturnNode() { this = TYieldReturnNode(cfn) and yrs.getExpr().getAControlFlowNode() = cfn } - /** Gets the underlying return node. */ - ExprReturnNode getUnderlyingNode() { result.getControlFlowNode() = cfn } + YieldReturnStmt getYieldReturnStmt() { result = yrs } override YieldReturnKind getKind() { any() } - override Callable getEnclosingCallable() { - result = this.getUnderlyingNode().getEnclosingCallable() - } + override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } - override Type getType() { - result = this.getUnderlyingNode().getEnclosingCallable().getReturnType() - } + override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } - override Location getLocation() { result = this.getUnderlyingNode().getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override string toString() { result = this.getUnderlyingNode().toString() } + override Location getLocationImpl() { result = yrs.getLocation() } + + override string toStringImpl() { result = yrs.toString() } } /** @@ -998,7 +1015,7 @@ private module ReturnNodes { * An implicit node is added in order to be able to track flow out of capturing * callables, as if an explicit `ref` parameter had been used: * - * ``` + * ```csharp * void M() { void M() { * int i = 0; int i = 0; * void Out() { void Out(ref int i0) { @@ -1143,7 +1160,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; @@ -1159,7 +1176,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 @@ -1172,84 +1189,313 @@ 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 } } } import OutNodes -private class FlowThroughLibraryCallableOutRefConfiguration extends ControlFlowReachabilityConfiguration { - FlowThroughLibraryCallableOutRefConfiguration() { - this = "FlowThroughLibraryCallableOutRefConfiguration" - } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor +/** + * Provides predicates related to flow through library code, based on + * the flow summaries in `LibraryTypeDataFlow.qll`. + */ +module LibraryFlow { + pragma[nomagic] + private ValueOrRefType getPreciseSourceProperty0( + Call call, CallableFlowSource source, AccessPath sourceAp, Property p ) { - exists(MethodCall mc, Parameter outRef | libraryFlowOutRef(mc, e, outRef, _) | - def.getTargetAccess() = mc.getArgumentForParameter(outRef) and - def instanceof AssignableDefinitions::OutRefDefinition and - scope = mc and - isSuccessor = true and - exactScope = false + exists(LibraryTypeDataFlow ltdf, Property p0 | + ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration()) and + sourceAp = AccessPath::property(p0) and + overridesOrImplementsSourceDecl(p, p0) and + result = source.getSourceType(call) ) } + + /** + * Gets a precise source property for source `source` and access path `sourceAp`, + * in the context of `call`. For example, in + * + * ```csharp + * var list = new List(); + * var count = list.Count(); + * ``` + * + * the step from `list` to `list.Count()`, which may be modeled as a read of + * the `Count` property from `ICollection`, can be strengthened to be a + * read of the `Count` property from `List`. + */ + pragma[nomagic] + private Property getPreciseSourceProperty( + Call call, CallableFlowSource source, AccessPath sourceAp + ) { + getPreciseSourceProperty0(call, source, sourceAp, result).hasMember(result) + } + + pragma[nomagic] + private ValueOrRefType getPreciseSinkProperty0( + Call call, CallableFlowSink sink, AccessPath sinkAp, Property p + ) { + exists(LibraryTypeDataFlow ltdf, Property p0 | + ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration()) and + sinkAp = AccessPath::property(p0) and + overridesOrImplementsSourceDecl(p, p0) and + result = sink.getSinkType(call) + ) + } + + /** + * Gets a precise sink property for sink `sink` and access path `sinkAp`, + * in the context of `call`. For example, in + * + * ```csharp + * var list = new List(); + * list.Add("taint"); + * var enumerator = list.getEnumerator(); + * ``` + * + * the step from `list` to `list.getEnumerator()`, which may be modeled as a + * read of a collection element followed by a store into the `Current` + * property, can be strengthened to be a store into the `Current` property + * from `List.Enumerator`, rather than the generic `Current` property + * from `IEnumerator`. + */ + pragma[nomagic] + private Property getPreciseSinkProperty(Call call, CallableFlowSink sink, AccessPath sinkAp) { + getPreciseSinkProperty0(call, sink, sinkAp, result).hasMember(result) + } + + /** + * Holds if data can flow from a node of kind `source` to a node of kind `sink`, + * using a call to a library callable. + * + * `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( + Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, + AccessPath sinkAp, boolean preservesValue + ) { + exists(LibraryTypeDataFlow ltdf, SourceDeclarationCallable c | + c = call.getTarget().getSourceDeclaration() + | + ltdf.callableFlow(source, sink, c, preservesValue) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() + or + preservesValue = true and + exists(AccessPath sourceAp0, AccessPath sinkAp0 | + ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c) and + ( + not sourceAp0 = AccessPath::property(_) and + sourceAp = sourceAp0 + or + exists(Property p | + overridesOrImplementsSourceDecl(p, + getPreciseSourceProperty(call, source, sourceAp0).getSourceDeclaration()) and + sourceAp = AccessPath::property(p) + ) + ) and + ( + not sinkAp0 = AccessPath::property(_) and + sinkAp = sinkAp0 + or + sinkAp = AccessPath::property(getPreciseSinkProperty(call, sink, sinkAp0)) + ) + ) + ) + } + + 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 + e1 = source.getSource(e2) and + scope = e2 and + exactScope = false and + isSuccessor = true + ) + } + } + + 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 + e2 = sink.getSink(e1) and + scope = e1 and + exactScope = false and + isSuccessor = false + ) + } + + override predicate candidateDef( + Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, + boolean isSuccessor + ) { + exists(CallableFlowSinkArg sink | + libraryFlow(e, _, _, sink, _, _) and + scope = e and + exactScope = false and + isSuccessor = true and + def.getTargetAccess() = sink.getArgument(e) and + def instanceof AssignableDefinitions::OutRefDefinition + ) + } + } } -/** - * Holds if `arg` is an argument of the method call `mc`, where the target - * of `mc` is a library callable that forwards `arg` to an `out`/`ref` argument - * `node`. Example: - * - * ``` - * int i; - * Int32.TryParse("42", out i); - * ``` - * - * `mc = Int32.TryParse("42", out i)`, `arg = "42"`, and `node` is the access - * to `i` in `out i`. - */ -predicate flowThroughLibraryCallableOutRef( - MethodCall mc, ExprNode arg, SsaDefinitionNode node, boolean preservesValue -) { - libraryFlowOutRef(mc, arg.getExpr(), _, preservesValue) and - any(FlowThroughLibraryCallableOutRefConfiguration x).hasNodePath(arg, node) +/** A data-flow node used to model flow through library code. */ +class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { + private ControlFlow::Node callCfn; + private CallableFlowSource source; + private AccessPath sourceAp; + private CallableFlowSink sink; + private AccessPath sinkAp; + private boolean preservesValue; + + LibraryCodeNode() { + this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue) + } + + /** Holds if this node is part of a value-preserving library step. */ + predicate preservesValue() { preservesValue = true } + + /** + * 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) + ) + 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() + ) + ) + } + + /** + * 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 Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } + + override DataFlowType getTypeBound() { + preservesValue = true and + sourceAp = AccessPath::empty() and + result = this.getPredecessor(_).getTypeBound() + or + exists(FieldOrProperty f | + sourceAp.getHead() = f.getContent() and + result = Gvn::getGlobalValueNumber(f.getType()) + ) + or + preservesValue = false and + result = this.getSuccessor(_).getTypeBound() + } + + override DotNet::Type getTypeImpl() { none() } + + override ControlFlow::Node getControlFlowNodeImpl() { result = callCfn } + + override Location getLocationImpl() { result = callCfn.getLocation() } + + override string toStringImpl() { result = "[library code] " + callCfn } } -/** - * Holds if the output from the delegate `delegate` flows to `out`. The delegate - * is passed as an argument to a library callable, which invokes the delegate. - * Example: - * - * ``` - * x.Select(Foo); - * ``` - * - * `delegate = Foo`, `out = x.Select(Foo)`, and `preservesValue = false`. - */ -predicate flowOutOfDelegateLibraryCall( - ImplicitDelegateOutNode delegate, ExprOutNode out, boolean preservesValue -) { - exists(DataFlowCall call, int i | - libraryFlowDelegateCallOut(call.getExpr(), _, out.getExpr(), preservesValue, i) and - delegate.isArgumentOf(call, i) and - out.getControlFlowNode() = call.getControlFlowNode() - ) -} +/** A field or a property. */ +private class FieldOrProperty extends Assignable, Modifiable { + FieldOrProperty() { + this instanceof Field + or + this instanceof Property + } -private class FieldLike extends Assignable, Modifiable { - FieldLike() { + /** Holds if this is either a field or a field-like property. */ + predicate isFieldLike() { this instanceof Field or this = any(Property p | @@ -1261,42 +1507,54 @@ private class FieldLike extends Assignable, Modifiable { ) ) } + + /** Gets the content that matches this field or property. */ + Content getContent() { + result.(FieldContent).getField() = this.getSourceDeclaration() + or + result.(PropertyContent).getProperty() = this.getSourceDeclaration() + } } -private class FieldLikeAccess extends AssignableAccess, QualifiableExpr { - FieldLikeAccess() { this.getTarget() instanceof FieldLike } +private class InstanceFieldOrProperty extends FieldOrProperty { + InstanceFieldOrProperty() { not this.isStatic() } } -private class FieldLikeRead extends FieldLikeAccess, AssignableRead { } +private class FieldOrPropertyAccess extends AssignableAccess, QualifiableExpr { + FieldOrPropertyAccess() { this.getTarget() instanceof FieldOrProperty } +} -/** - * Holds if the field-like read `flr` is not completely determined by explicit - * SSA updates. - */ -private predicate hasNonlocalValue(FieldLikeRead flr) { - flr = any(Ssa::ImplicitUntrackedDefinition udef).getARead() - or - exists(Ssa::Definition def, Ssa::ImplicitDefinition idef | - def.getARead() = flr and - idef = def.getAnUltimateDefinition() - | - idef instanceof Ssa::ImplicitEntryDefinition or - idef instanceof Ssa::ImplicitCallDefinition - ) +private class FieldOrPropertyRead extends FieldOrPropertyAccess, AssignableRead { + /** + * Holds if this field-like read is not completely determined by explicit + * SSA updates. + */ + predicate hasNonlocalValue() { + this = any(Ssa::ImplicitUntrackedDefinition udef).getARead() + or + exists(Ssa::Definition def, Ssa::ImplicitDefinition idef | + def.getARead() = this and + idef = def.getAnUltimateDefinition() + | + idef instanceof Ssa::ImplicitEntryDefinition or + idef instanceof Ssa::ImplicitCallDefinition + ) + } } /** A write to a static field/property. */ private class StaticFieldLikeJumpNode extends NonLocalJumpNode, ExprNode { - FieldLike fl; - FieldLikeRead flr; + FieldOrProperty fl; + FieldOrPropertyRead flr; ExprNode succ; StaticFieldLikeJumpNode() { fl.isStatic() and + fl.isFieldLike() and fl.getAnAssignedValue() = this.getExpr() and fl.getAnAccess() = flr and flr = succ.getExpr() and - hasNonlocalValue(flr) + flr.hasNonlocalValue() } override ExprNode getAJumpSuccessor(boolean preservesValue) { @@ -1306,41 +1564,6 @@ private class StaticFieldLikeJumpNode extends NonLocalJumpNode, ExprNode { predicate jumpStep = jumpStepImpl/2; -/** - * A reference contained in an object. Currently limited to instance fields - * and field-like instance properties. - */ -class Content extends TContent { - /** Gets a textual representation of this content. */ - abstract string toString(); - - abstract Location getLocation(); - - /** Gets the type of the object containing this content. */ - abstract DataFlowType getContainerType(); - - /** Gets the type of this content. */ - abstract DataFlowType getType(); -} - -private class FieldLikeContent extends Content, TFieldLikeContent { - private FieldLike f; - - FieldLikeContent() { this = TFieldLikeContent(f) } - - FieldLike getField() { result = f } - - override string toString() { result = f.toString() } - - override Location getLocation() { result = f.getLocation() } - - override DataFlowType getContainerType() { - result = Gvn::getGlobalValueNumber(f.getDeclaringType()) - } - - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } -} - private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration { StoreStepConfiguration() { this = "StoreStepConfiguration" } @@ -1349,11 +1572,11 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio ) { exactScope = false and isSuccessor = false and - instanceFieldLikeAssign(scope, _, e1, e2) + fieldOrPropertyAssign(scope, _, e1, e2) or exactScope = false and isSuccessor = false and - instanceFieldLikeInit(e2, _, e1) and + fieldOrPropertyInit(e2, _, e1) and scope = e2 } } @@ -1368,7 +1591,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration ) { exactScope = false and isSuccessor = true and - e1 = e2.(FieldLikeRead).getQualifier() and + fieldOrPropertyRead(e1, _, e2) and scope = e2 } } @@ -1432,20 +1655,22 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } } - private class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + 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() } } } @@ -1508,3 +1733,29 @@ 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 } + +/** Holds if `n` should be hidden from path explanations. */ +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 +} 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 d5dff3b8b21..d4bffa735bb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -5,6 +5,7 @@ private import DataFlowDispatch private import DataFlowPrivate private import semmle.code.csharp.Caching private import semmle.code.csharp.controlflow.Guards +private import semmle.code.csharp.Unification /** * An element, viewed as a node in a data flow graph. Either an expression @@ -38,26 +39,49 @@ class Node extends TNode { /** Gets the type of this node. */ cached - DotNet::Type getType() { none() } + final DotNet::Type getType() { + Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl() + } - /** Gets an upper bound on the type of this node. */ - DotNet::Type getTypeBound() { result = this.getType() } // stub implementation + /** 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 + ) + } /** 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. @@ -98,31 +122,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" - } } /** @@ -136,8 +135,7 @@ class ParameterNode extends Node { this.(SsaDefinitionNode).getDefinition() instanceof ImplicitCapturedParameterNodeImpl::SsaCapturedEntryDefinition or this = TInstanceParameterNode(_) or - this = TCilParameterNode(_) or - this = TTaintedParameterNode(_) + this = TCilParameterNode(_) } /** Gets the parameter corresponding to this node, if any. */ @@ -231,3 +229,60 @@ class BarrierGuard extends Guard { ) } } + +/** + * A reference contained in an object. This is either a field or a property. + */ +class Content extends TContent { + /** Gets a textual representation of this content. */ + string toString() { none() } + + /** Gets the location of this content. */ + Location getLocation() { none() } + + /** Gets the type of the object containing this content. */ + deprecated DataFlowType getContainerType() { none() } + + /** Gets the type of this content. */ + deprecated DataFlowType getType() { none() } +} + +/** A reference to a field. */ +class FieldContent extends Content, TFieldContent { + private Field f; + + FieldContent() { this = TFieldContent(f) } + + /** Gets the field that is referenced. */ + Field getField() { result = f } + + override string toString() { result = f.toString() } + + override Location getLocation() { result = f.getLocation() } + + deprecated override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(f.getDeclaringType()) + } + + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } +} + +/** A reference to a property. */ +class PropertyContent extends Content, TPropertyContent { + private Property p; + + PropertyContent() { this = TPropertyContent(p) } + + /** Gets the property that is referenced. */ + Property getProperty() { result = p } + + override string toString() { result = p.toString() } + + override Location getLocation() { result = p.getLocation() } + + deprecated override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(p.getDeclaringType()) + } + + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } +} 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 9c41d5b1e3e..56b2cdbccf5 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -118,6 +118,9 @@ library class DelegateArgumentToLibraryCallable extends Expr { /** Gets the call that this argument belongs to. */ Call getCall() { result = call } + /** Gets the index of this delegate argument in the call. */ + int getArgumentIndex() { this = this.getCall().getArgument(result) } + /** Gets the delegate type of this argument. */ DelegateType getDelegateType() { result = dt } 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 70047de7433..2c7ad5ec391 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -45,9 +45,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) { exactScope = false and ( - // Taint propagation using library code - LocalFlow::libraryFlow(e1, e2, scope, isSuccessor, false) - or // Taint from assigned value to element qualifier (`x[i] = 0`) exists(AssignExpr ae | e1 = ae.getRValue() and @@ -162,11 +159,8 @@ module Cached { Stages::DataFlowStage::forceCachingInSameStage() and any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) or - nodeTo = nodeFrom.(TaintedParameterNode).getUnderlyingNode() - or - nodeFrom = nodeTo.(TaintedReturnNode).getUnderlyingNode() - or - flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) + nodeFrom.(DataFlow::ExprNode).getControlFlowNode() = + nodeTo.(YieldReturnNode).getControlFlowNode() or localTaintStepCil(nodeFrom, nodeTo) or @@ -180,7 +174,13 @@ module Cached { access.(PropertyRead).getQualifier() = nodeFrom.asExpr() ) or - flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, false) + exists(LibraryCodeNode n | not n.preservesValue() | + n = nodeTo and + nodeFrom = n.getPredecessor(AccessPath::empty()) + or + n = nodeFrom and + nodeTo = n.getSuccessor(AccessPath::empty()) + ) } } 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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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..32338220d5c 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -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 d1e1017e0d1..842c374ecd1 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -566,10 +566,10 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess * } * ``` */ -class IndexerRead extends IndexerAccess, AssignableRead { - override IndexerRead getANextRead() { result = AssignableRead.super.getANextRead() } +class IndexerRead extends IndexerAccess, ElementRead { + override IndexerRead getANextRead() { result = ElementRead.super.getANextRead() } - override IndexerRead getAReachableRead() { result = AssignableRead.super.getAReachableRead() } + override IndexerRead getAReachableRead() { result = ElementRead.super.getAReachableRead() } } /** @@ -586,7 +586,7 @@ class IndexerRead extends IndexerAccess, AssignableRead { * } * ``` */ -class IndexerWrite extends IndexerAccess, AssignableWrite { } +class IndexerWrite extends IndexerAccess, ElementWrite { } /** * An access to a virtual indexer - an indexer that is virtual or defined in @@ -818,7 +818,7 @@ class ArrayAccess extends ElementAccess, @array_access_expr { * } * ``` */ -class ArrayRead extends ArrayAccess, AssignableRead { } +class ArrayRead extends ArrayAccess, ElementRead { } /** * An access to an array that updates the underlying value, for example @@ -830,7 +830,7 @@ class ArrayRead extends ArrayAccess, AssignableRead { } * } * ``` */ -class ArrayWrite extends ArrayAccess, AssignableWrite { } +class ArrayWrite extends ArrayAccess, ElementWrite { } /** * An access to a namespace, for example `System` in `nameof(System)`. diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 72596c42abc..c0659176841 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -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`. */ 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 68dfc910911..b439f958a01 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -3,7 +3,7 @@ */ import csharp -import semmle.code.csharp.dataflow.LibraryTypeDataFlow +private import semmle.code.csharp.dataflow.LibraryTypeDataFlow /** Definitions relating to the `Json.NET` package. */ module JsonNET { 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/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/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 94d0192fe18..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ /dev/null @@ -1,320 +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 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/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 94d0192fe18..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll +++ /dev/null @@ -1,320 +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 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/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 89% 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 c5a0b98598f..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 @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -19,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 f0a19c633d7..6409269ce5b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -370,6 +370,10 @@ | Finally.cs:211:13:211:29 | ...; | Finally.cs:213:9:213:24 | ... = ... | 8 | | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:28 | [finally: exception(Exception)] ... = ... | 4 | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:28 | [finally: exception(ExceptionA)] ... = ... | 4 | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:31:220:35 | "Try" | 6 | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | 1 | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:224:13:224:38 | call to method WriteLine | 5 | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | exit M11 | 8 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:8:29:8:32 | access to parameter args | 3 | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:6:10:6:11 | exit M1 | 1 | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | 1 | @@ -396,14 +400,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/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 5db89e6d2ca..577f2f6ccbe 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -1621,6 +1621,24 @@ dominance | Finally.cs:213:9:213:12 | this access | Finally.cs:213:22:213:24 | "1" | | Finally.cs:213:9:213:25 | ...; | Finally.cs:213:9:213:12 | this access | | Finally.cs:213:22:213:24 | "1" | Finally.cs:213:9:213:24 | ... = ... | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:217:5:231:5 | {...} | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:218:9:229:9 | try {...} ... | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:219:9:221:9 | {...} | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:37 | ...; | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:224:31:224:37 | "Catch" | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:224:13:224:38 | call to method WriteLine | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:228:13:228:41 | ...; | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:230:9:230:34 | ...; | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:228:31:228:39 | "Finally" | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:228:13:228:40 | call to method WriteLine | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:216:10:216:12 | exit M11 | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:230:27:230:32 | "Done" | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:9:230:33 | call to method WriteLine | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:7:5:10:5 | {...} | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:8:29:8:32 | access to parameter args | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | exit M1 | @@ -1665,93 +1683,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 | @@ -4515,6 +4636,24 @@ postDominance | Finally.cs:213:9:213:24 | ... = ... | Finally.cs:213:22:213:24 | "1" | | Finally.cs:213:9:213:25 | ...; | Finally.cs:211:13:211:28 | ... = ... | | Finally.cs:213:22:213:24 | "1" | Finally.cs:213:9:213:12 | this access | +| Finally.cs:216:10:216:12 | exit M11 | Finally.cs:230:9:230:33 | call to method WriteLine | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:216:10:216:12 | enter M11 | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:217:5:231:5 | {...} | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:218:9:229:9 | try {...} ... | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:219:9:221:9 | {...} | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:37 | ...; | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:224:31:224:37 | "Catch" | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:223:9:225:9 | {...} | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:224:13:224:39 | ...; | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:224:13:224:38 | call to method WriteLine | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:228:31:228:39 | "Finally" | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:227:9:229:9 | {...} | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:228:13:228:41 | ...; | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:230:27:230:32 | "Done" | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:228:13:228:40 | call to method WriteLine | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:9:230:34 | ...; | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:29:8:32 | access to parameter args | @@ -4559,93 +4698,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 | @@ -6943,6 +7185,13 @@ blockDominance | Finally.cs:211:13:211:29 | ...; | Finally.cs:211:13:211:29 | ...; | | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | enter M11 | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:227:9:229:9 | {...} | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:227:9:229:9 | {...} | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | exit M1 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | @@ -7001,14 +7250,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 ...; | @@ -8747,6 +8997,13 @@ postBlockDominance | Finally.cs:211:13:211:29 | ...; | Finally.cs:211:13:211:29 | ...; | | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | enter M11 | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | enter M11 | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:227:9:229:9 | {...} | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:6:10:6:11 | enter M1 | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:6:10:6:11 | exit M1 | @@ -8807,14 +9064,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 d6c78dda8ae..bb34142d550 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -1742,6 +1742,26 @@ nodeEnclosing | Finally.cs:213:9:213:24 | ... = ... | Finally.cs:195:10:195:12 | M10 | | Finally.cs:213:9:213:25 | ...; | Finally.cs:195:10:195:12 | M10 | | Finally.cs:213:22:213:24 | "1" | Finally.cs:195:10:195:12 | M10 | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:216:10:216:12 | exit M11 | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:216:10:216:12 | M11 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | M1 | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:6:10:6:11 | M1 | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:6:10:6:11 | M1 | @@ -1793,99 +1813,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 | @@ -3548,6 +3672,10 @@ blockEnclosing | Finally.cs:211:13:211:29 | ...; | Finally.cs:195:10:195:12 | M10 | | Finally.cs:211:13:211:29 | [finally: exception(Exception)] ...; | Finally.cs:195:10:195:12 | M10 | | Finally.cs:211:13:211:29 | [finally: exception(ExceptionA)] ...; | Finally.cs:195:10:195:12 | M10 | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:216:10:216:12 | M11 | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:216:10:216:12 | M11 | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:6:10:6:11 | M1 | | Foreach.cs:6:10:6:11 | exit M1 | Foreach.cs:6:10:6:11 | M1 | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | M1 | @@ -3574,13 +3702,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 29ef1c6475b..4cc60894d75 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1169,6 +1169,24 @@ | Finally.cs:213:9:213:24 | ... = ... | Finally.cs:213:9:213:12 | this access | | Finally.cs:213:9:213:25 | ...; | Finally.cs:213:9:213:25 | ...; | | Finally.cs:213:22:213:24 | "1" | Finally.cs:213:22:213:24 | "1" | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:217:5:231:5 | {...} | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:218:9:229:9 | try {...} ... | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:219:9:221:9 | {...} | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:31:220:35 | "Try" | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:37 | ...; | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:31:220:35 | "Try" | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:222:9:225:9 | catch {...} | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:223:9:225:9 | {...} | +| Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:224:31:224:37 | "Catch" | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:224:13:224:39 | ...; | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:224:31:224:37 | "Catch" | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:227:9:229:9 | {...} | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:228:31:228:39 | "Finally" | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:228:13:228:41 | ...; | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:228:31:228:39 | "Finally" | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:230:27:230:32 | "Done" | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:230:9:230:34 | ...; | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:27:230:32 | "Done" | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:7:5:10:5 | {...} | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:29:8:32 | access to parameter args | | Foreach.cs:8:22:8:24 | String arg | Foreach.cs:8:22:8:24 | String arg | @@ -1208,74 +1226,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 622637f5c9d..fb1a799cb55 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -1652,6 +1652,31 @@ | Finally.cs:213:9:213:24 | ... = ... | Finally.cs:213:9:213:24 | ... = ... | normal | | Finally.cs:213:9:213:25 | ...; | Finally.cs:213:9:213:24 | ... = ... | normal | | Finally.cs:213:22:213:24 | "1" | Finally.cs:213:22:213:24 | "1" | normal | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:230:9:230:33 | call to method WriteLine | normal | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:228:13:228:40 | call to method WriteLine | normal | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | normal | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | normal | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | call to method WriteLine | normal | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:13:220:36 | call to method WriteLine | throw(Exception) | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:31:220:35 | "Try" | normal | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:31:220:35 | "Try" | throw(OutOfMemoryException) | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:224:13:224:38 | call to method WriteLine | normal | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:38 | call to method WriteLine | normal | +| Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:224:13:224:38 | call to method WriteLine | normal | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:224:13:224:38 | call to method WriteLine | normal | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:224:31:224:37 | "Catch" | normal | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:228:13:228:40 | call to method WriteLine | normal | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:228:13:228:40 | call to method WriteLine | normal | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:228:13:228:40 | call to method WriteLine | normal | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:228:31:228:39 | "Finally" | normal | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:230:9:230:33 | call to method WriteLine | normal | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:230:9:230:33 | call to method WriteLine | normal | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:27:230:32 | "Done" | normal | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | empty | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | empty | | Foreach.cs:8:22:8:24 | String arg | Foreach.cs:8:22:8:24 | String arg | normal | @@ -1695,74 +1720,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/Finally.cs b/csharp/ql/test/library-tests/controlflow/graph/Finally.cs index 20bb7ec213f..d130862a4df 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Finally.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Finally.cs @@ -212,4 +212,21 @@ public class Finally } this.Field = "1"; } + + void M11() + { + try + { + Console.WriteLine("Try"); + } + catch + { + Console.WriteLine("Catch"); + } + finally + { + Console.WriteLine("Finally"); + } + Console.WriteLine("Done"); + } } 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 4756e86100b..f790cd0e90c 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1818,6 +1818,27 @@ | Finally.cs:213:9:213:24 | ... = ... | Finally.cs:195:10:195:12 | exit M10 | semmle.label | successor | | Finally.cs:213:9:213:25 | ...; | Finally.cs:213:9:213:12 | this access | semmle.label | successor | | Finally.cs:213:22:213:24 | "1" | Finally.cs:213:9:213:24 | ... = ... | semmle.label | successor | +| Finally.cs:216:10:216:12 | enter M11 | Finally.cs:217:5:231:5 | {...} | semmle.label | successor | +| Finally.cs:217:5:231:5 | {...} | Finally.cs:218:9:229:9 | try {...} ... | semmle.label | successor | +| Finally.cs:218:9:229:9 | try {...} ... | Finally.cs:219:9:221:9 | {...} | semmle.label | successor | +| Finally.cs:219:9:221:9 | {...} | Finally.cs:220:13:220:37 | ...; | semmle.label | successor | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:222:9:225:9 | catch {...} | semmle.label | exception(Exception) | +| Finally.cs:220:13:220:36 | call to method WriteLine | Finally.cs:227:9:229:9 | {...} | semmle.label | successor | +| Finally.cs:220:13:220:37 | ...; | Finally.cs:220:31:220:35 | "Try" | semmle.label | successor | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:220:13:220:36 | call to method WriteLine | semmle.label | successor | +| Finally.cs:220:31:220:35 | "Try" | Finally.cs:222:9:225:9 | catch {...} | semmle.label | exception(OutOfMemoryException) | +| Finally.cs:222:9:225:9 | catch {...} | Finally.cs:223:9:225:9 | {...} | semmle.label | successor | +| Finally.cs:223:9:225:9 | {...} | Finally.cs:224:13:224:39 | ...; | semmle.label | successor | +| Finally.cs:224:13:224:38 | call to method WriteLine | Finally.cs:227:9:229:9 | {...} | semmle.label | successor | +| Finally.cs:224:13:224:39 | ...; | Finally.cs:224:31:224:37 | "Catch" | semmle.label | successor | +| Finally.cs:224:31:224:37 | "Catch" | Finally.cs:224:13:224:38 | call to method WriteLine | semmle.label | successor | +| Finally.cs:227:9:229:9 | {...} | Finally.cs:228:13:228:41 | ...; | semmle.label | successor | +| Finally.cs:228:13:228:40 | call to method WriteLine | Finally.cs:230:9:230:34 | ...; | semmle.label | successor | +| Finally.cs:228:13:228:41 | ...; | Finally.cs:228:31:228:39 | "Finally" | semmle.label | successor | +| Finally.cs:228:31:228:39 | "Finally" | Finally.cs:228:13:228:40 | call to method WriteLine | semmle.label | successor | +| Finally.cs:230:9:230:33 | call to method WriteLine | Finally.cs:216:10:216:12 | exit M11 | semmle.label | successor | +| Finally.cs:230:9:230:34 | ...; | Finally.cs:230:27:230:32 | "Done" | semmle.label | successor | +| Finally.cs:230:27:230:32 | "Done" | Finally.cs:230:9:230:33 | call to method WriteLine | semmle.label | successor | | Foreach.cs:6:10:6:11 | enter M1 | Foreach.cs:7:5:10:5 | {...} | semmle.label | successor | | Foreach.cs:7:5:10:5 | {...} | Foreach.cs:8:29:8:32 | access to parameter args | semmle.label | successor | | Foreach.cs:8:9:9:13 | foreach (... ... in ...) ... | Foreach.cs:6:10:6:11 | exit M1 | semmle.label | empty | @@ -1871,93 +1892,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 0a7201f1280..f6d10fdb2ba 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -710,19 +710,21 @@ entryPoint | Finally.cs:147:10:147:11 | M8 | Finally.cs:148:5:170:5 | {...} | | Finally.cs:176:10:176:11 | M9 | Finally.cs:177:5:193:5 | {...} | | Finally.cs:195:10:195:12 | M10 | Finally.cs:196:5:214:5 | {...} | +| Finally.cs:216:10:216:12 | M11 | Finally.cs:217:5:231:5 | {...} | | Foreach.cs:6:10:6:11 | M1 | Foreach.cs:7:5:10:5 | {...} | | Foreach.cs:12:10:12:11 | M2 | Foreach.cs:13:5:16:5 | {...} | | Foreach.cs:18:10:18:11 | M3 | Foreach.cs:19:5:22:5 | {...} | | 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 3aa1d59c012..cad303fa914 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -7,18 +7,15 @@ | CSharp7.cs:17:9:17:11 | this | CSharp7.cs:17:18:17:22 | this access | | CSharp7.cs:21:9:21:11 | this | CSharp7.cs:21:16:21:20 | this access | | CSharp7.cs:22:9:22:11 | this | CSharp7.cs:22:16:22:20 | this access | -| CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:9:22:11 | value | | CSharp7.cs:22:9:22:11 | value | CSharp7.cs:22:24:22:28 | access to parameter value | | CSharp7.cs:25:5:25:27 | this | CSharp7.cs:16:9:16:13 | this access | | CSharp7.cs:26:6:26:28 | this | CSharp7.cs:26:35:26:39 | this access | -| CSharp7.cs:31:19:31:19 | i | CSharp7.cs:31:19:31:19 | i | | CSharp7.cs:31:19:31:19 | i | CSharp7.cs:33:16:33:16 | access to parameter i | | CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:16:33:20 | ... > ... | | CSharp7.cs:33:16:33:16 | access to parameter i | CSharp7.cs:33:24:33:24 | access to parameter i | | CSharp7.cs:33:24:33:24 | access to parameter i | CSharp7.cs:33:16:33:59 | ... ? ... : ... | | CSharp7.cs:33:28:33:59 | throw ... | CSharp7.cs:33:16:33:59 | ... ? ... : ... | | CSharp7.cs:41:13:41:21 | "tainted" | CSharp7.cs:41:9:41:21 | SSA def(x) | -| CSharp7.cs:44:19:44:19 | x | CSharp7.cs:44:19:44:19 | x | | CSharp7.cs:44:19:44:19 | x | CSharp7.cs:46:13:46:13 | access to parameter x | | CSharp7.cs:46:13:46:13 | access to parameter x | CSharp7.cs:46:9:46:13 | SSA def(y) | | CSharp7.cs:49:10:49:10 | this | CSharp7.cs:51:9:51:24 | this access | @@ -65,7 +62,6 @@ | CSharp7.cs:78:31:78:31 | access to local variable a | CSharp7.cs:78:27:78:32 | (..., ...) | | CSharp7.cs:79:23:79:24 | "" | CSharp7.cs:79:22:79:28 | (..., ...) | | CSharp7.cs:79:27:79:27 | access to local variable x | CSharp7.cs:79:22:79:28 | (..., ...) | -| CSharp7.cs:82:21:82:21 | x | CSharp7.cs:82:21:82:21 | x | | CSharp7.cs:82:21:82:21 | x | CSharp7.cs:84:20:84:20 | access to parameter x | | CSharp7.cs:84:16:84:24 | (..., ...) | CSharp7.cs:84:16:84:26 | access to field a | | CSharp7.cs:84:20:84:20 | access to parameter x | CSharp7.cs:84:16:84:24 | (..., ...) | @@ -116,19 +112,15 @@ | CSharp7.cs:119:19:119:20 | access to local variable m2 | CSharp7.cs:119:19:119:26 | access to field Item1 | | CSharp7.cs:123:28:123:36 | "DefUse3" | CSharp7.cs:123:22:123:36 | ... = ... | | CSharp7.cs:129:9:129:12 | this | CSharp7.cs:135:24:135:25 | this access | -| CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:20:131:20 | x | | CSharp7.cs:131:20:131:20 | x | CSharp7.cs:131:32:131:32 | access to parameter x | | CSharp7.cs:131:32:131:32 | access to parameter x | CSharp7.cs:131:32:131:36 | ... + ... | | CSharp7.cs:131:36:131:36 | 1 | CSharp7.cs:131:32:131:36 | ... + ... | -| CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:22:133:22 | t | | CSharp7.cs:133:22:133:22 | t | CSharp7.cs:133:39:133:39 | access to parameter t | | CSharp7.cs:135:24:135:25 | this access | CSharp7.cs:155:16:155:17 | this access | -| CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:29:139:29 | x | | CSharp7.cs:139:29:139:29 | x | CSharp7.cs:139:34:139:34 | access to parameter x | | CSharp7.cs:139:34:139:34 | access to parameter x | CSharp7.cs:139:34:139:38 | ... + ... | | CSharp7.cs:139:38:139:38 | 1 | CSharp7.cs:139:34:139:38 | ... + ... | | CSharp7.cs:141:9:141:51 | this | CSharp7.cs:141:38:141:39 | this access | -| CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:20:141:20 | x | | CSharp7.cs:141:20:141:20 | x | CSharp7.cs:141:26:141:26 | access to parameter x | | CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:26:141:30 | ... > ... | | CSharp7.cs:141:26:141:26 | access to parameter x | CSharp7.cs:141:41:141:41 | access to parameter x | @@ -137,17 +129,13 @@ | CSharp7.cs:141:38:141:46 | call to local function f7 | CSharp7.cs:141:34:141:46 | ... + ... | | CSharp7.cs:141:50:141:50 | 0 | CSharp7.cs:141:26:141:50 | ... ? ... : ... | | CSharp7.cs:143:9:143:31 | this | CSharp7.cs:143:26:143:27 | this access | -| CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:20:143:20 | x | | CSharp7.cs:143:20:143:20 | x | CSharp7.cs:143:29:143:29 | access to parameter x | | CSharp7.cs:145:9:149:9 | this | CSharp7.cs:148:20:148:21 | this access | | CSharp7.cs:147:13:147:35 | this | CSharp7.cs:147:30:147:31 | this access | -| CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:24:147:24 | x | | CSharp7.cs:147:24:147:24 | x | CSharp7.cs:147:33:147:33 | access to parameter x | | CSharp7.cs:158:10:158:17 | this | CSharp7.cs:170:9:170:9 | this access | -| CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:18:161:18 | t | | CSharp7.cs:161:18:161:18 | t | CSharp7.cs:161:24:161:24 | access to parameter t | | CSharp7.cs:163:9:168:9 | this | CSharp7.cs:166:13:166:16 | this access | -| CSharp7.cs:163:26:163:26 | u | CSharp7.cs:163:26:163:26 | u | | CSharp7.cs:163:26:163:26 | u | CSharp7.cs:167:22:167:22 | access to parameter u | | CSharp7.cs:165:13:165:43 | this | CSharp7.cs:165:37:165:40 | this access | | CSharp7.cs:166:13:166:16 | this access | CSharp7.cs:167:20:167:20 | this access | @@ -156,13 +144,10 @@ | CSharp7.cs:176:16:176:30 | SSA def(src) | CSharp7.cs:181:23:181:25 | access to local variable src | | CSharp7.cs:176:22:176:30 | "tainted" | CSharp7.cs:176:16:176:30 | SSA def(src) | | CSharp7.cs:177:9:177:40 | this | CSharp7.cs:177:31:177:31 | this access | -| CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:25:177:25 | s | | CSharp7.cs:177:25:177:25 | s | CSharp7.cs:177:33:177:33 | access to parameter s | | CSharp7.cs:177:31:177:34 | call to local function g | CSharp7.cs:177:31:177:39 | ... + ... | | CSharp7.cs:177:38:177:39 | "" | CSharp7.cs:177:31:177:39 | ... + ... | -| CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:25:178:25 | s | | CSharp7.cs:178:25:178:25 | s | CSharp7.cs:178:31:178:31 | access to parameter s | -| CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:25:179:25 | s | | CSharp7.cs:179:25:179:25 | s | CSharp7.cs:179:37:179:37 | access to parameter s | | CSharp7.cs:181:21:181:21 | this access | CSharp7.cs:182:21:182:21 | this access | | CSharp7.cs:181:23:181:25 | [post] access to local variable src | CSharp7.cs:182:23:182:25 | access to local variable src | @@ -189,9 +174,7 @@ | CSharp7.cs:199:26:199:35 | [post] this access | CSharp7.cs:200:9:200:18 | this access | | CSharp7.cs:199:26:199:35 | this access | CSharp7.cs:200:9:200:18 | this access | | CSharp7.cs:199:33:199:34 | access to local variable r1 | CSharp7.cs:200:16:200:17 | access to local variable r1 | -| CSharp7.cs:203:24:203:24 | p | CSharp7.cs:203:24:203:24 | p | | CSharp7.cs:203:24:203:24 | p | CSharp7.cs:206:20:206:20 | access to parameter p | -| CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:28:205:28 | q | | CSharp7.cs:205:28:205:28 | q | CSharp7.cs:205:44:205:44 | access to parameter q | | CSharp7.cs:216:13:216:17 | false | CSharp7.cs:216:9:216:17 | SSA def(x) | | CSharp7.cs:217:17:217:17 | 0 | CSharp7.cs:217:16:217:23 | (..., ...) | @@ -248,13 +231,16 @@ | 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:32:284:35 | item | | 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 | call to method Select | +| 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 | access to property Value | +| 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/callablereturnsarg/Common.qll b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll index 4b2626c73b3..2ddbd6cf123 100644 --- a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll @@ -1,12 +1,23 @@ import csharp private import semmle.code.csharp.controlflow.Guards +private predicate outRefDef(DataFlow::ExprNode ne, int outRef) { + exists(Ssa::ExplicitDefinition def, Parameter outRefParameter | + outRefParameter.isOutOrRef() and + ne.getExpr() = def.getADefinition().getSource() and + def.isLiveOutRefParameterDefinition(outRefParameter) and + outRef = outRefParameter.getPosition() + ) +} + class Configuration extends DataFlow::Configuration { Configuration() { this = "Configuration" } - override predicate isSource(DataFlow::Node source) { any() } + override predicate isSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode } - override predicate isSink(DataFlow::Node sink) { any() } + override predicate isSink(DataFlow::Node sink) { + any(Callable c).canReturn(sink.asExpr()) or outRefDef(sink, _) + } override predicate isBarrier(DataFlow::Node node) { exists(AbstractValues::NullValue nv | node.(GuardedDataFlowNode).mustHaveValue(nv) | @@ -24,15 +35,9 @@ predicate flowOutFromParameter(DataFlow::Configuration c, Parameter p) { } predicate flowOutFromParameterOutOrRef(DataFlow::Configuration c, Parameter p, int outRef) { - exists( - DataFlow::ExprNode ne, Ssa::ExplicitDefinition def, DataFlow::ParameterNode np, - Parameter outRefParameter - | - outRefParameter.isOutOrRef() and + exists(DataFlow::ExprNode ne, DataFlow::ParameterNode np | + outRefDef(ne, outRef) and np.getParameter() = p and - ne.getExpr() = def.getADefinition().getSource() and - def.isLiveOutRefParameterDefinition(outRefParameter) and - c.hasFlow(np, ne) and - outRef = outRefParameter.getPosition() + c.hasFlow(np, ne) ) } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs new file mode 100644 index 00000000000..3565ba0b6ea --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -0,0 +1,231 @@ +// semmle-extractor-options: /r:System.Linq.dll +using System; +using System.Collections.Generic; +using System.Linq; + +public class CollectionFlow +{ + public class A { } + + public void ArrayInitializerFlow() + { + var a = new A(); + var @as = new[] { a }; + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void ArrayInitializerNoFlow(A other) + { + var a = new A(); + var @as = new[] { other }; + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + public void ArrayAssignmentFlow() + { + var a = new A(); + var @as = new A[1]; + @as[0] = a; + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow + } + + public void ArrayAssignmentNoFlow(A other) + { + var a = new A(); + var @as = new A[1]; + @as[0] = other; + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + public void ListAssignmentFlow() + { + var a = new A(); + var list = new List(); + list[0] = a; + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListAssignmentNoFlow(A other) + { + var list = new List(); + list[0] = other; + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void ListInitializerFlow() + { + var a = new A(); + var list = new List() { a }; + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListInitializerNoFlow(A other) + { + var list = new List() { other }; + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void ListAddFlow() + { + var a = new A(); + var list = new List(); + list.Add(a); + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListAddNoFlow(A other) + { + var list = new List(); + list.Add(other); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void DictionaryAssignmentFlow() + { + var a = new A(); + var dict = new Dictionary(); + dict[0] = a; + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictValuesFirst(dict)); // flow + } + + public void DictionaryAssignmentNoFlow(A other) + { + var dict = new Dictionary(); + dict[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 DictionaryValueInitializerFlow() + { + 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 [MISSING] + Sink(DictValuesFirst(dict)); // flow + } + + public void DictionaryValueInitializerNoFlow(A other) + { + 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] + } + + public void DictionaryKeyInitializerNoFlow(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(); + var @as = new[] { a }; + foreach (var x in @as) + Sink(x); // flow + } + + public void ForeachNoFlow(A other) + { + var @as = new[] { other }; + foreach (var x in @as) + Sink(x); // no flow + } + + public void ArrayGetEnumeratorFlow() + { + var a = new A(); + var @as = new[] { a }; + var enumerator = @as.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // flow + } + + public void ArrayGetEnumeratorNoFlow(A other) + { + var @as = new[] { other }; + var enumerator = @as.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // no flow + } + + public void ListGetEnumeratorFlow() + { + var a = new A(); + var list = new List(); + list.Add(a); + var enumerator = list.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // flow [MISSING] + } + + public static void Sink(T t) { } + + public static void SinkElem(T[] ts) => Sink(ts[0]); + + public static void SinkListElem(IList list) => Sink(list[0]); + + public static void SinkDictValue(IDictionary dict) => Sink(dict[0]); + + public static void SinkDictKey(IDictionary dict) => Sink(dict.Keys.First()); + + public static T First(T[] ts) => ts[0]; + + public static T ListFirst(IList list) => list[0]; + + public static T DictIndexZero(IDictionary dict) => dict[0]; + + public static T DictFirstValue(IDictionary dict) => dict.First().Value; + + public static T DictValuesFirst(IDictionary dict) => dict.Values.First(); + + public static T DictKeysFirst(IDictionary dict) => dict.Keys.First(); + + public static T DictFirstKey(IDictionary dict) => dict.First().Key; +} diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected new file mode 100644 index 00000000000..c6cc298ea94 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -0,0 +1,235 @@ +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 | +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: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 | +#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 | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql new file mode 100644 index 00000000000..d1290562252 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql @@ -0,0 +1,23 @@ +/** + * @kind path-problem + */ + +import csharp +import DataFlow::PathGraph + +class Conf extends TaintTracking::Configuration { + Conf() { this = "ArrayFlowConf" } + + override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodCall mc | + mc.getTarget().hasName("Sink") and + mc.getAnArgument() = sink.asExpr() + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(source, sink) +select source, source, sink, "$@", sink, sink.toString() diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index baae38c1780..3d0a0a83ed5 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -201,6 +201,20 @@ 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: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 | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | H.cs:165:21:165:21 | access to local variable a [FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | +| H.cs:165:17:165:28 | (...) ... : B | H.cs:166:14:166:14 | access to local variable b | +| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | H.cs:167:14:167:14 | access to local variable b [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | H.cs:165:21:165:28 | access to field FieldA : B | +| 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 | 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 | @@ -434,6 +448,22 @@ nodes | H.cs:147:17:147:32 | call to method Through : A | semmle.label | call to method Through : A | | 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: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 | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA, FieldB] | semmle.label | [post] access to local variable a [FieldA, FieldB] | +| H.cs:164:19:164:19 | [post] access to local variable a [FieldA] : B | semmle.label | [post] access to local variable a [FieldA] : B | +| H.cs:164:22:164:22 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| H.cs:165:17:165:28 | (...) ... : B | semmle.label | (...) ... : B | +| H.cs:165:17:165:28 | (...) ... [FieldB] : Object | semmle.label | (...) ... [FieldB] : Object | +| H.cs:165:21:165:21 | access to local variable a [FieldA, FieldB] | semmle.label | access to local variable a [FieldA, FieldB] | +| H.cs:165:21:165:21 | access to local variable a [FieldA] : B | semmle.label | access to local variable a [FieldA] : B | +| H.cs:165:21:165:28 | access to field FieldA : B | semmle.label | access to field FieldA : B | +| H.cs:165:21:165:28 | access to field FieldA [FieldB] : Object | semmle.label | access to field FieldA [FieldB] : Object | +| 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 | #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 | @@ -481,3 +511,5 @@ nodes | H.cs:114:14:114:21 | access to field FieldB | H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:114:14:114:21 | access to field FieldB | $@ | H.cs:112:20:112:31 | object creation of type Object : Object | object creation of type Object : Object | | H.cs:131:14:131:19 | call to method Get | H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:131:14:131:19 | call to method Get | $@ | H.cs:130:20:130:31 | object creation of type Object : Object | object creation of type Object : Object | | 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 | diff --git a/csharp/ql/test/library-tests/dataflow/fields/H.cs b/csharp/ql/test/library-tests/dataflow/fields/H.cs index 1ddb6ec2821..1d214fc89da 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/H.cs +++ b/csharp/ql/test/library-tests/dataflow/fields/H.cs @@ -150,5 +150,22 @@ public class H Sink(b); // no flow } + void SetNested(A a, object o) + { + var b = new B(); + b.FieldB = o; + a.FieldA = b; + } + + void M8() + { + var a = new A(); + var o = new object(); + SetNested(a, o); + var b = (B) a.FieldA; + Sink(b); // flow (from `new B()` inside `SetNested`) + Sink(b.FieldB); // flow + } + public static void Sink(object o) { } } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 38c978be390..ca81fb55904 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -28,15 +28,15 @@ | 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:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | +| 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 | | 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/DataFlowEdges.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected deleted file mode 100644 index b386a148705..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.expected +++ /dev/null @@ -1,3816 +0,0 @@ -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted | -| 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 | -| 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 | -| 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:61:36:61:42 | access to parameter tainted | -| 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:11:17:11:32 | SSA def(sink27) | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | 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:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access : Capture | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) | -| 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:20:21:20:36 | SSA def(sink28) | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter 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:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 | -| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter 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:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | -| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg : String[] | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted : String | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : 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] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(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:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String | -| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String | -| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 | -| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 : String | -| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 | -| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) | -| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | -| Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(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:19 | this access : Capture | Capture.cs:83:9:83:19 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:83:9:83:19 | this access : Capture | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 : String | -| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) | -| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) : String | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | -| Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(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:19 | this access : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 : String | -| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) | -| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) : String | -| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 | -| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | -| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) | -| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | -| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg : 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:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 : String | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) | -| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) : String | -| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | -| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) | -| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | -| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | -| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) | -| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | -| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 | -| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 : 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:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 : String | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted | -| 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 | -| 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 | -| 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 | -| 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:168:25:168:31 | access to parameter tainted | -| 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 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) | -| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String | -| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) | -| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) | -| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String | -| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) | -| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) : String | -| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 | -| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String | -| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | -| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg : 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 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String | -| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | -| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | -| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | -| 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:160:13:160:38 | SSA def(sink36) | -| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:160:13:160:38 | SSA def(sink36) : 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:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String | -| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) | -| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String | -| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) | -| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 : String | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p : String | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(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:194:25:194:31 | access to parameter tainted | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted | -| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted : String | -| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted | -| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted : String | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String | -| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id : String | -| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 | -| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String | -| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) | -| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) : String | -| 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:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 | -| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id : String | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : 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:18:15:18:29 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| 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:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo | -| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo | -| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:240:26:240:35 | sinkParam1 | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | -| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 | -| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | -| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 | -| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:359:41:359:41 | x | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:359:41:359:41 | x | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter 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:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this : DataFlow | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| 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:404:9:404:11 | value | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this : DataFlow | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : 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:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | 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:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : 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:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | 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:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| 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:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| 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:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| 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:76:15:76:19 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | 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:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| 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:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | 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:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| 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:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| 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:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : T | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String[] | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String[] | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String[] | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : T | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String[] | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String[] | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String[] | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call : T | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : 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:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | 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:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : 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:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| 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:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : 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:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this : DataFlow | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 : String | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this : DataFlow | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 : String | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this : DataFlow | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted : T | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this : DataFlow | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this : DataFlow | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this : DataFlow | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call : String | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : 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:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : 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:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : 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:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this : DataFlow | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this : DataFlow | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : String | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : String | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : String | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : String | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : String | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : Object | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : String | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| 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 | -| 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:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : 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 | -| 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 : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : 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): true] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x : String | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return : T | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| 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 | -| 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 | -| 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:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| 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): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| 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:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : 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 | -| 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 : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| 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 | -| 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 | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this : This | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this : This | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access : This | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this : Sub | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql deleted file mode 100644 index d6d43ededd0..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowEdges.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp -import DataFlow -import semmle.code.csharp.dataflow.internal.DataFlowPrivate - -class ConfigAny extends Configuration { - ConfigAny() { this = "ConfigAny" } - - override predicate isSource(Node source) { - source instanceof PostUpdateNode implies source.asExpr() instanceof ObjectCreation - } - - override predicate isSink(Node sink) { - sink instanceof PostUpdateNode implies sink.asExpr() instanceof ObjectCreation - } -} - -query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index cc1d49f3557..d3ca6b87625 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -1,46 +1,26 @@ 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 | @@ -75,7 +55,7 @@ edges | 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:234:26:234:35 | sinkParam0 : 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 | @@ -84,7 +64,7 @@ edges | 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:240:26:240:35 | sinkParam1 : 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 | @@ -100,31 +80,31 @@ edges | 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:359:41:359:41 | x : 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:250:26:250:35 | sinkParam4 : 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:359:41:359:41 | x : 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:373:52:373:52 | x : 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:373:52:373:52 | x : 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:265:26:265:35 | sinkParam7 : 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:373:52:373:52 | x : 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:404:9:404:11 | value : 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 | @@ -149,38 +129,39 @@ edges | 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:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| 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:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| 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:22:189:42 | object creation of type Lazy [Value] : 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 | | 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 | @@ -202,50 +183,30 @@ 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 | @@ -300,46 +261,47 @@ nodes | 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:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : 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: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:234:26:234:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | semmle.label | "taint source" : String | +| 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 | | 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 | @@ -368,12 +330,12 @@ nodes | 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:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | +| 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:404:41:404:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | access to local variable sink20 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| 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 | | 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 | @@ -390,20 +352,20 @@ nodes | 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 | | 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:318:16:318: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:323:13:323: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:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | +| 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 | | 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:237:15:237:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| 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:247:15:247:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| 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 | | 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 | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 586a0ef9ca8..2b712d5c2f8 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -54,25 +54,25 @@ | 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:82:22:82:95 | call to method Select | return | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:59:82:72 | call to method First | return | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:59:84:72 | call to method First | return | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:106:86:119 | call to method First | return | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:86:125:86:135 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | -| GlobalDataFlow.cs:88:43:88:61 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:64:88:69 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | -| GlobalDataFlow.cs:90:75:90:88 | call to method First | return | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:90:91:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:112:90:117 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | +| 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 | @@ -89,28 +89,30 @@ | 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:24:112:90 | call to method SelectEven | return | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | +| 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:134 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:57:116:70 | call to method First | return | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:116:123:116:133 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:104:118:117 | call to method First | return | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:118:123:118:133 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | -| GlobalDataFlow.cs:120:41:120:55 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:58:120:63 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | -| GlobalDataFlow.cs:122:41:122:59 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:62:122:68 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | -| GlobalDataFlow.cs:124:46:124:58 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:61:124:66 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:61:124:66 | [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 | @@ -130,6 +132,7 @@ | 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) | @@ -150,32 +153,42 @@ | 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:209:76:209:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select | return | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select | yield return | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:37:210:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | +| 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:37:212:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select | return | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select | yield return | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select | return | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select | yield return | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:41:220:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select | return | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | +| 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:39 | call to method Select | yield return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | +| 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:37:226:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select | return | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select | yield return | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [implicit call] delegate creation of type Func | return | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call | return | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call | return | GlobalDataFlow.cs:431:44:431:47 | delegate call | +| 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 | | 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 41630b7fd8f..83003aaea66 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -77,17 +77,17 @@ public class DataFlow var sink3 = ""; ReturnRef(sink2, ref sink3, ref sink3); Check(sink3); - var sink13 = ((IEnumerable)new string[] { sink3 }).SelectEven(x => x); + var sink13 = ((IEnumerable)new string[] { sink3 }).SelectEven(x => x).First(); Check(sink13); - var sink14 = ((IEnumerable)new string[] { sink13.First() }).Select(ReturnCheck); + var sink14 = ((IEnumerable)new string[] { sink13 }).Select(ReturnCheck).First(); Check(sink14); - var sink15 = ((IEnumerable)new string[] { sink14.First() }).Zip(((IEnumerable)new string[] { "" }), (x, y) => x); + var sink15 = ((IEnumerable)new string[] { sink14 }).Zip(((IEnumerable)new string[] { "" }), (x, y) => x).First(); Check(sink15); - var sink16 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15.First() }), (x, y) => y); + var sink16 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15 }), (x, y) => y).First(); Check(sink16); - var sink17 = sink14.Aggregate("", (acc, s) => acc + s, x => x); + var sink17 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc + s, x => x); Check(sink17); - var sink18 = ((IEnumerable)new string[] { "" }).Aggregate(sink14.First(), (acc, s) => acc + s, x => x); + var sink18 = ((IEnumerable)new string[] { "" }).Aggregate(sink14, (acc, s) => acc + s, x => x); Check(sink18); int sink21; Int32.TryParse(sink18, out sink21); @@ -109,19 +109,19 @@ public class DataFlow Check(nonSink0); ReturnRef(sink1, ref sink1, ref nonSink0); Check(nonSink0); - var nonSink1 = ((IEnumerable)new string[] { nonSink0 }).SelectEven(x => x); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { nonSink0 }).Select(x => x); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { sink14.First() }).Zip(((IEnumerable)new string[] { "" }), (x, y) => y); - Check(nonSink1); - nonSink1 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15.First() }), (x, y) => x); - Check(nonSink1); - nonSink0 = sink14.Aggregate("", (acc, s) => acc, x => x); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).SelectEven(x => x).First(); Check(nonSink0); - nonSink0 = sink14.Aggregate("", (acc, s) => acc + s, x => ""); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).Select(x => x).First(); Check(nonSink0); - nonSink0 = nonSink1.Aggregate(sink1, (acc, s) => s, x => x); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Zip(((IEnumerable)new string[] { "" }), (x, y) => y).First(); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { "" }).Zip(((IEnumerable)new string[] { sink15 }), (x, y) => x).First(); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc, x => x); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { sink14 }).Aggregate("", (acc, s) => acc + s, x => ""); + Check(nonSink0); + nonSink0 = ((IEnumerable)new string[] { nonSink0 }).Aggregate(sink1, (acc, s) => s, x => x); Check(nonSink0); int nonSink2; Int32.TryParse(nonSink0, out nonSink2); @@ -158,7 +158,7 @@ public class DataFlow var sink8 = ""; OutRef(ref sink8); Check(sink8); - var sink12 = OutYield(); + var sink12 = OutYield().First(); Check(sink12); var sink23 = TaintedParam(nonSink0); // even though the argument is not tainted, the parameter is considered tainted Check(sink23); @@ -202,30 +202,32 @@ public class DataFlow Check(nonSink0); } - public void M2(IQueryable tainted, IQueryable notTainted) + public void M2() { + IQueryable tainted = new[] { "taint source" }.AsQueryable(); + IQueryable notTainted = new[] { "not tainted" }.AsQueryable(); // Flow into a callable via library call, tainted Func f1 = sinkParam10 => { Check(sinkParam10); return sinkParam10; }; System.Linq.Expressions.Expression> f2 = x => ReturnCheck2(x); - var sink24 = tainted.Select(f1); + var sink24 = tainted.Select(f1).First(); Check(sink24); - var sink25 = tainted.Select(f2); + var sink25 = tainted.Select(f2).First(); Check(sink25); - var sink26 = tainted.Select(ReturnCheck3); + var sink26 = tainted.Select(ReturnCheck3).First(); Check(sink26); // Flow into a callable via library call, not tainted Func f3 = nonSinkParam => { Check(nonSinkParam); return nonSinkParam; }; System.Linq.Expressions.Expression> f4 = x => NonReturnCheck(x); - var nonSink = notTainted.Select(f1); + var nonSink = notTainted.Select(f1).First(); Check(nonSink); - nonSink = notTainted.Select(f2); + nonSink = notTainted.Select(f2).First(); Check(nonSink); - nonSink = notTainted.Select(f3); + nonSink = notTainted.Select(f3).First(); Check(nonSink); - nonSink = notTainted.Select(f4); + nonSink = notTainted.Select(f4).First(); Check(nonSink); - nonSink = notTainted.Select(ReturnCheck3); + nonSink = notTainted.Select(ReturnCheck3).First(); Check(nonSink); } diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 10d873cc2fc..57fd2c9e0c3 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -37,22 +37,22 @@ | 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:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | +| 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 | | 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/TaintTrackingEdges.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.expected deleted file mode 100644 index bd9d777b9dd..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.expected +++ /dev/null @@ -1,5782 +0,0 @@ -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:14:9:14:18 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:25:9:25:18 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:7:10:7:11 | this : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:7:20:7:26 | tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:7:20:7:26 | tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:14:9:14:20 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:25:9:25:20 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:33:9:33:40 | [implicit argument] tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:61:36:61:42 | access to parameter tainted | -| Capture.cs:7:20:7:26 | tainted : Object | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted | -| 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 | -| 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 | -| 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:61:36:61:42 | access to parameter tainted | -| 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:11:17:11:32 | SSA def(sink27) | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:11:26:11:32 | 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:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:17:11:32 | SSA def(sink27) : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:11:17:11:32 | SSA def(sink27) : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:11:26:11:32 | access to parameter tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 : String | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:25:9:25:18 | this access : Capture | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:14:9:14:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) | -| 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:20:21:20:36 | SSA def(sink28) | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:20:30:20:36 | access to parameter 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:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:21:20:36 | SSA def(sink28) : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:20:21:20:36 | SSA def(sink28) : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:20:30:20:36 | access to parameter tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 : String | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:49:9:49:27 | this access : Capture | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:25:9:25:18 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 | -| Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:27:43:27:45 | arg | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:27:43:27:45 | arg : String | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : Object | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:27:45 | arg : String | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:27:43:27:45 | arg | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:27:43:27:45 | arg : String | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:31:20:31:22 | access to parameter arg | -| Capture.cs:27:43:27:45 | arg : String[] | Capture.cs:31:20:31:22 | access to parameter arg : String | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:27:30:32:9 | SSA def(captureIn3) : Func | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 | -| Capture.cs:27:43:32:9 | (...) => ... : Func | Capture.cs:33:30:33:39 | access to local variable captureIn3 : Func | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:29:26:29:32 | access to parameter 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:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:17:29:32 | SSA def(sink29) : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:29:17:29:32 | SSA def(sink29) : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:29:26:29:32 | access to parameter tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 : String | -| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | -| Capture.cs:31:20:31:22 | access to parameter arg : String | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:27:43:27:45 | arg : String[] | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 | -| Capture.cs:33:9:33:21 | array creation of type String[] : String[] | Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:33:9:33:40 | call to method Select : IEnumerable | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:9:33:40 | call to method Select : IEnumerable | Capture.cs:33:9:33:50 | call to method ToArray : String[] | -| Capture.cs:33:17:33:19 | " " : String | Capture.cs:33:9:33:21 | array creation of type String[] | -| Capture.cs:33:17:33:19 | " " : String | Capture.cs:33:9:33:21 | array creation of type String[] : String[] | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:40 | call to method Select | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:40 | call to method Select : IEnumerable | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:50 | call to method ToArray | -| Capture.cs:33:30:33:39 | [output] access to local variable captureIn3 : String | Capture.cs:33:9:33:50 | call to method ToArray : String[] | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:37:28:37:34 | access to parameter tainted : String | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:35:9:39:9 | SSA capture def(tainted) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:37:17:37:34 | SSA def(nonSink0) : String | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 | -| Capture.cs:37:28:37:34 | access to parameter tainted : String | Capture.cs:38:19:38:26 | access to local variable nonSink0 : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:45:32:45:38 | access to parameter tainted : String | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:43:13:47:13 | SSA capture def(tainted) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:45:21:45:38 | SSA def(nonSink0) : String | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 | -| Capture.cs:45:32:45:38 | access to parameter tainted : String | Capture.cs:46:23:46:30 | access to local variable nonSink0 : String | -| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access | -| Capture.cs:49:9:49:27 | this access : Capture | Capture.cs:61:9:61:19 | this access : Capture | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:50:33:50:40 | nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:50:33:50:40 | nonSink0 : String | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : Object | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | -| Capture.cs:50:33:50:40 | nonSink0 : String | Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:50:50:50:55 | sink39 | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : Object | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : 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] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | -| Capture.cs:52:13:59:14 | [implicit argument] nonSink0 : String | Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(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:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:52:23:59:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String | -| Capture.cs:52:23:59:13 | SSA capture def(nonSink0) : String | Capture.cs:54:23:54:30 | access to parameter nonSink0 : String | -| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:55:27:58:17 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 : String | -| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 | -| Capture.cs:61:21:61:33 | "not tainted" : String | Capture.cs:50:33:50:40 | nonSink0 : String | -| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 | -| Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:71:9:71:19 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:83:9:83:19 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:64:10:64:12 | this : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) | -| Capture.cs:66:25:66:26 | "" : String | Capture.cs:66:16:66:26 | SSA def(sink30) : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | -| Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(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:19 | this access : Capture | Capture.cs:83:9:83:19 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:83:9:83:19 | this access : Capture | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:71:9:71:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 : String | -| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) | -| Capture.cs:74:25:74:26 | "" : String | Capture.cs:74:16:74:26 | SSA def(sink31) : String | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | -| Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(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:19 | this access : Capture | Capture.cs:109:9:109:28 | this access | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:109:9:109:28 | this access : Capture | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:83:9:83:19 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 : String | -| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) | -| Capture.cs:86:25:86:26 | "" : String | Capture.cs:86:16:86:26 | SSA def(sink32) : String | -| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 | -| Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:87:44:87:46 | arg | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:87:44:87:46 | arg : String | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : Object | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:87:46 | arg : String | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:87:44:87:46 | arg | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:87:44:87:46 | arg : String | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:90:20:90:22 | access to parameter arg | -| Capture.cs:87:44:87:46 | arg : String[] | Capture.cs:90:20:90:22 | access to parameter arg : String | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:87:30:91:9 | SSA def(captureOut3) : Func | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 | -| Capture.cs:87:44:91:9 | (...) => ... : Func | Capture.cs:92:30:92:40 | access to local variable captureOut3 : Func | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | -| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) | -| Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | -| Capture.cs:90:20:90:22 | access to parameter arg : String | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:87:44:87:46 | arg : String[] | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 | -| Capture.cs:92:9:92:21 | array creation of type String[] : String[] | Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : 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:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 : String | -| Capture.cs:92:9:92:41 | call to method Select : IEnumerable | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:9:92:41 | call to method Select : IEnumerable | Capture.cs:92:9:92:51 | call to method ToArray : String[] | -| Capture.cs:92:17:92:19 | " " : String | Capture.cs:92:9:92:21 | array creation of type String[] | -| Capture.cs:92:17:92:19 | " " : String | Capture.cs:92:9:92:21 | array creation of type String[] : String[] | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:41 | call to method Select | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:41 | call to method Select : IEnumerable | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:51 | call to method ToArray | -| Capture.cs:92:30:92:40 | [output] access to local variable captureOut3 : String | Capture.cs:92:9:92:51 | call to method ToArray : String[] | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:95:16:95:28 | SSA def(nonSink0) : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:95:27:95:28 | "" : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 | -| Capture.cs:100:15:100:22 | access to local variable nonSink0 : String | Capture.cs:110:15:110:22 | access to local variable nonSink0 : String | -| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access | -| Capture.cs:109:9:109:28 | this access : Capture | Capture.cs:121:9:121:33 | this access : Capture | -| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) | -| Capture.cs:111:25:111:26 | "" : String | Capture.cs:111:16:111:26 | SSA def(sink40) : String | -| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:114:23:116:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | -| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) | -| Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a | -| Capture.cs:117:23:119:13 | (...) => ... : Action | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) | -| Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | -| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) | -| Capture.cs:118:28:118:40 | "not tainted" : String | Capture.cs:118:17:118:40 | SSA def(nonSink0) : String | -| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 | -| Capture.cs:121:9:121:35 | SSA call def(nonSink0) : String | Capture.cs:122:30:122:37 | access to local variable nonSink0 : 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:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 : String | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:132:9:132:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:144:9:144:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:125:10:125:16 | this : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:125:25:125:31 | tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:125:25:125:31 | tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:132:9:132:25 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:144:9:144:25 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:153:9:153:45 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:160:22:160:38 | [implicit argument] tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:168:25:168:31 | access to parameter tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:168:25:168:31 | access to parameter tainted : String | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:194:25:194:31 | access to parameter tainted | -| Capture.cs:125:25:125:31 | tainted : Object | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted | -| 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 | -| 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 | -| 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 | -| 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:168:25:168:31 | access to parameter tainted | -| 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 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) | -| Capture.cs:127:25:127:26 | "" : String | Capture.cs:127:16:127:26 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String | -| Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | Capture.cs:130:22:130:28 | access to parameter tainted : String | -| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) | -| Capture.cs:130:13:130:28 | SSA def(sink33) : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:130:22:130:28 | access to parameter tainted : String | Capture.cs:130:13:130:28 | SSA def(sink33) : String | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:144:9:144:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:132:9:132:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:128:9:131:9 | SSA capture def(tainted) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) | -| Capture.cs:135:25:135:26 | "" : String | Capture.cs:135:16:135:26 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String | -| Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | Capture.cs:140:26:140:32 | access to parameter tainted : String | -| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:140:17:140:32 | SSA def(sink34) : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:140:26:140:32 | access to parameter tainted : String | Capture.cs:140:17:140:32 | SSA def(sink34) : String | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:160:22:160:36 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:144:9:144:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:138:13:141:13 | SSA capture def(tainted) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) | -| Capture.cs:147:25:147:26 | "" : String | Capture.cs:147:16:147:26 | SSA def(sink35) : String | -| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 | -| Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:148:48:148:50 | arg | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:148:48:148:50 | arg : String | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : Object | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:148:50 | arg : String | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:148:48:148:50 | arg | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:148:48:148:50 | arg : String | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:151:20:151:22 | access to parameter arg | -| Capture.cs:148:48:148:50 | arg : String[] | Capture.cs:151:20:151:22 | access to parameter arg : String | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:148:30:152:9 | SSA def(captureThrough3) : Func | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 | -| Capture.cs:148:48:152:9 | (...) => ... : Func | Capture.cs:153:30:153:44 | access to local variable captureThrough3 : Func | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String | -| Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | Capture.cs:150:22:150:28 | access to parameter tainted : String | -| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:150:13:150:28 | SSA def(sink35) : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:150:22:150:28 | access to parameter tainted : String | Capture.cs:150:13:150:28 | SSA def(sink35) : String | -| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | -| Capture.cs:151:20:151:22 | access to parameter arg : String | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:148:48:148:50 | arg : String[] | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 | -| Capture.cs:153:9:153:21 | array creation of type String[] : String[] | Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : 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 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:148:48:152:9 | SSA capture def(tainted) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | call to method Select : IEnumerable | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:9:153:45 | call to method Select : IEnumerable | Capture.cs:153:9:153:55 | call to method ToArray : String[] | -| Capture.cs:153:17:153:19 | " " : String | Capture.cs:153:9:153:21 | array creation of type String[] | -| Capture.cs:153:17:153:19 | " " : String | Capture.cs:153:9:153:21 | array creation of type String[] : String[] | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:45 | call to method Select | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:45 | call to method Select : IEnumerable | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:55 | call to method ToArray | -| Capture.cs:153:30:153:44 | [output] access to local variable captureThrough3 : String | Capture.cs:153:9:153:55 | call to method ToArray : String[] | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String | -| Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | Capture.cs:158:20:158:26 | access to parameter tainted : String | -| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | -| Capture.cs:158:20:158:26 | access to parameter tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | -| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:160:13:160:38 | SSA def(sink36) : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:168:9:168:23 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:160:22:160:36 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:156:9:159:9 | SSA capture def(tainted) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 | -| 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:160:13:160:38 | SSA def(sink36) | -| Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:160:13:160:38 | SSA def(sink36) : 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:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 : String | -| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) | -| Capture.cs:163:22:163:23 | "" : String | Capture.cs:163:13:163:23 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:164:37:164:37 | p | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:164:37:164:37 | p : String | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : Object | Capture.cs:166:22:166:22 | access to parameter p : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String | -| Capture.cs:164:37:164:37 | p : String | Capture.cs:166:22:166:22 | access to parameter p : String | -| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) | -| Capture.cs:166:13:166:22 | SSA def(sink37) : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:166:22:166:22 | access to parameter p : String | Capture.cs:166:13:166:22 | SSA def(sink37) : String | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:185:9:185:32 | this access : Capture | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:168:9:168:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| 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:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 : String | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:164:37:164:37 | p : String | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(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:194:25:194:31 | access to parameter tainted | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:171:16:171:28 | SSA def(nonSink0) : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:171:27:171:28 | "" : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted | -| Capture.cs:172:9:175:9 | SSA capture def(tainted) : String | Capture.cs:174:24:174:30 | access to parameter tainted : String | -| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 | -| Capture.cs:176:15:176:22 | access to local variable nonSink0 : String | Capture.cs:186:15:186:22 | access to local variable nonSink0 : String | -| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted | -| Capture.cs:180:13:183:13 | SSA capture def(tainted) : String | Capture.cs:182:28:182:34 | access to parameter tainted : String | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:194:22:194:23 | this access : Capture | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:185:9:185:32 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:188:26:188:26 | s | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : Object | Capture.cs:191:20:191:22 | [implicit argument] s : String | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String | -| Capture.cs:188:26:188:26 | s : String | Capture.cs:191:20:191:22 | [implicit argument] s : String | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String | -| Capture.cs:190:13:190:28 | SSA capture def(s) : String | Capture.cs:190:27:190:27 | access to parameter s : String | -| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:190:27:190:27 | access to parameter s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:190:13:190:28 | SSA capture def(s) : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | [implicit argument] s : String | Capture.cs:191:20:191:22 | call to local function M : String | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id | -| Capture.cs:191:20:191:22 | call to local function M : String | Capture.cs:196:20:196:25 | call to local function Id : String | -| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 | -| Capture.cs:194:13:194:32 | SSA def(sink38) : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String | -| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access | -| Capture.cs:194:22:194:23 | this access : Capture | Capture.cs:196:20:196:21 | this access : Capture | -| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) | -| Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:194:13:194:32 | SSA def(sink38) : String | -| 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:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 : String | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id | -| Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 | -| Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:196:9:196:25 | SSA def(nonSink0) : String | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 | -| Capture.cs:196:20:196:25 | call to local function Id : String | Capture.cs:197:15:197:22 | access to local variable nonSink0 : String | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:188:26:188:26 | s : String | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id | -| Capture.cs:196:23:196:24 | "" : String | Capture.cs:196:20:196:25 | call to local function Id : String | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Action | Capture.cs:204:9:204:9 | access to parameter a : Action | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:202:34:202:34 | a | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:202:34:202:34 | a : Action | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:204:9:204:9 | access to parameter a | -| Capture.cs:202:34:202:34 | a : Object | Capture.cs:204:9:204:9 | access to parameter a : Action | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:14:17:14:17 | this : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:17:9:17:40 | SSA def(DataFlow.Test.SinkField0) : 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:18:15:18:29 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| 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:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:21:9:21:42 | SSA def(DataFlow.Test.NonSinkField0) : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:21:30:21:42 | "not tainted" : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:22:15:22:32 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:25:9:25:44 | SSA def(DataFlow.Test.SinkProperty0) : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:31:33:31:47 | access to field SinkField0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:25:30:25:44 | access to field SinkField0 : 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 | -| 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:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:29:9:29:50 | SSA def(DataFlow.Test.NonSinkProperty0) : String | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:29:33:29:50 | access to field NonSinkField0 : String | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| 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:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo | -| GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:36:13:36:58 | SSA def(methodInfo) : MethodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod : MethodInfo | GlobalDataFlow.cs:38:9:38:18 | access to local variable methodInfo : MethodInfo | -| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:13:37:54 | SSA def(args) : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:20:37:54 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:33:38:36 | access to local variable args : Object[] | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:240:26:240:35 | sinkParam1 | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | -| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 | -| GlobalDataFlow.cs:41:16:41:17 | "" : String | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | -| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 | -| GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : Object | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 : String | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:44:24:44:60 | SSA def(in2) : Action | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 | -| GlobalDataFlow.cs:44:30:44:60 | (...) => ... : Action | GlobalDataFlow.cs:45:9:45:11 | access to local variable in2 : Action | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : Object | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | GlobalDataFlow.cs:48:56:48:68 | access to parameter nonSinkParam1 : String | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:48:24:48:69 | SSA def(nonIn1) : Action | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 | -| GlobalDataFlow.cs:48:33:48:69 | (...) => ... : Action | GlobalDataFlow.cs:49:9:49:14 | access to local variable nonIn1 : Action | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 | -| GlobalDataFlow.cs:49:16:49:17 | "" : String | GlobalDataFlow.cs:48:33:48:45 | nonSinkParam1 : String | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:52:15:52:17 | delegate creation of type Action : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:359:41:359:41 | x | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : Object | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x | -| GlobalDataFlow.cs:53:15:53:15 | x : T | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:53:15:53:25 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : T | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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 | -| 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:359:41:359:41 | x | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:54:23:54:41 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:55:23:55:25 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| 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 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:56:9:56:48 | SSA def(DataFlow.myDelegate) : MyDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate | -| GlobalDataFlow.cs:56:22:56:48 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : Object | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter 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:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:57:23:57:32 | access to field myDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| 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 | -| 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:373:52:373:52 | x | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : Object | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:60:15:60:51 | (...) => ... : Action | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:60:54:60:66 | "not tainted" : String | GlobalDataFlow.cs:359:41:359:41 | x : String | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:61:23:61:75 | delegate creation of type MyDelegate : MyDelegate | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : Object | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:61:78:61:90 | "not tainted" : String | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this | -| GlobalDataFlow.cs:64:9:64:18 | this access : DataFlow | GlobalDataFlow.cs:404:9:404:11 | this : DataFlow | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| 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:404:9:404:11 | value | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this | -| GlobalDataFlow.cs:67:9:67:21 | this access : DataFlow | GlobalDataFlow.cs:410:9:410:11 | this : DataFlow | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:67:25:67:37 | "not tainted" : String | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : 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:71:15:71:19 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | 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:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:70:13:70:46 | SSA def(sink0) : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 : T | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : 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:73:15:73:19 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | 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:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:72:13:72:101 | SSA def(sink1) : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : Object | GlobalDataFlow.cs:72:21:72:101 | (...) ... : Object | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | GlobalDataFlow.cs:72:21:72:101 | (...) ... : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| 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:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:72:79:72:100 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| 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:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| 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:76:15:76:19 | access to local variable sink2 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | 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:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 : T | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:77:13:77:22 | SSA def(sink3) : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:77:21:77:22 | "" : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| 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:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | 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:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | access to local variable sink3 : String | GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:78:41:78:45 | access to local variable sink3 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| 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:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:80:13:80:85 | SSA def(sink13) : IEnumerable | -| 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:81:15:81:20 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:80:44:80:65 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 | -| GlobalDataFlow.cs:80:59:80:63 | access to local variable sink3 : T | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:79:80:79 | x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : Object | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : String | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x | -| GlobalDataFlow.cs:80:79:80:79 | x : T | GlobalDataFlow.cs:80:84:80:84 | access to parameter x : T | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:80:79:80:84 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:80:84:80:84 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First | -| GlobalDataFlow.cs:82:59:82:64 | access to local variable sink13 : IEnumerable | GlobalDataFlow.cs:82:59:82:72 | call to method First : String | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:59:82:72 | call to method First : String | GlobalDataFlow.cs:82:44:82:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:13:82:95 | SSA def(sink14) : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:22:82:95 | call to method Select | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:82:22:82:95 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String[] | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:84:59:84:72 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:84:59:84:64 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] | -| GlobalDataFlow.cs:84:59:84:72 | call to method First : String | GlobalDataFlow.cs:84:44:84:74 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:82:84:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:118:84:119 | "" : String | GlobalDataFlow.cs:84:103:84:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:13:84:136 | SSA def(sink15) : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:22:84:136 | call to method Zip | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:84:22:84:136 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : IEnumerable | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:126:84:126 | x | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:126:84:126 | x : String | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:135:84:135 | access to parameter x | -| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... | -| GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:23:86:62 | (...) ... : String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] | -| GlobalDataFlow.cs:86:59:86:60 | "" : String | GlobalDataFlow.cs:86:44:86:62 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String[] | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:86:106:86:119 | call to method First : String | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:86:106:86:111 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] | -| GlobalDataFlow.cs:86:106:86:119 | call to method First : String | GlobalDataFlow.cs:86:91:86:121 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:13:86:136 | SSA def(sink16) : IEnumerable | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:22:86:136 | call to method Zip | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:22:86:136 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 : IEnumerable | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : IEnumerable | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:129:86:129 | y | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:129:86:129 | y : String | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:135:86:135 | access to parameter y | -| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... | -| GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:39:88:40 | "" : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:44:88:46 | acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:44:88:46 | acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:44:88:46 | acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:49:88:49 | s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : IEnumerable | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:49:88:49 | s | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:49:88:49 | s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : Object | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:49:88:49 | s : String | GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:55:88:57 | access to parameter acc : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... | -| GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:61:88:61 | access to parameter s : String | GlobalDataFlow.cs:88:55:88:61 | ... + ... : String | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : Object | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:64:88:64 | x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:64:88:64 | x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:64 | x : String | GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:13:88:70 | SSA def(sink17) : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:88:22:88:70 | call to method Aggregate : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 : String | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... | -| GlobalDataFlow.cs:88:69:88:69 | access to parameter x : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String[] | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:23:90:62 | (...) ... : String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] | -| GlobalDataFlow.cs:90:59:90:60 | "" : String | GlobalDataFlow.cs:90:44:90:62 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:90:75:90:80 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:92:90:94 | acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:92:90:94 | acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:92:90:94 | acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : IEnumerable | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:97:90:97 | s | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:97:90:97 | s : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:109:90:109 | access to parameter s | -| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:103:90:105 | access to parameter acc : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:112:90:112 | x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:112:90:112 | x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:112 | x : String | GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:13:90:118 | SSA def(sink18) : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:90:22:90:118 | call to method Aggregate : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... | -| GlobalDataFlow.cs:90:117:90:117 | access to parameter x : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:93:24:93:29 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) : Int32 | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 : Int32 | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:23:96:28 | access to local variable sink18 : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) : Boolean | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 : Boolean | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:100:13:100:33 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:100:24:100:33 | call to method Return : String | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:100:31:100:32 | "" : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 | -| GlobalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : Object | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:102:9:102:103 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | GlobalDataFlow.cs:103:15:103:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : Object | GlobalDataFlow.cs:102:20:102:103 | (...) ... : Object | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | GlobalDataFlow.cs:102:20:102:103 | (...) ... : String | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | GlobalDataFlow.cs:102:20:102:103 | (...) ... : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:102:78:102:102 | array creation of type Object[] : Object[] | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:102:93:102:100 | access to local variable nonSink0 : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:104:19:104:20 | "" : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:105:15:105:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:281:32:281:32 | x : Object | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : String | GlobalDataFlow.cs:281:32:281:32 | x : String | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:106:19:106:23 | access to local variable sink1 : T | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:107:15:107:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:108:19:108:20 | "" : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : String | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:108:27:108:34 | access to local variable nonSink0 : T | GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:108:41:108:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:109:15:109:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : Object | GlobalDataFlow.cs:287:32:287:32 | x : Object | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : String | GlobalDataFlow.cs:287:32:287:32 | x : String | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:110:30:110:34 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:110:19:110:23 | access to local variable sink1 : T | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : Object | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : Object | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : String | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : String | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 | -| GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | GlobalDataFlow.cs:124:39:124:43 | access to local variable sink1 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : String | GlobalDataFlow.cs:287:50:287:50 | z : String | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:110:41:110:48 | access to local variable nonSink0 : T | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:111:15:111:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:112:13:112:90 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | GlobalDataFlow.cs:113:15:113:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : IEnumerable | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | GlobalDataFlow.cs:426:71:426:71 | e : String[] | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:25:112:70 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:112:46:112:70 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 | -| GlobalDataFlow.cs:112:61:112:68 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:84:112:84 | x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : Object | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : String | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x | -| GlobalDataFlow.cs:112:84:112:84 | x : T | GlobalDataFlow.cs:112:89:112:89 | access to parameter x : T | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:112:84:112:89 | (...) => ... : Func | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:112:89:112:89 | access to parameter x : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : String | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : IEnumerable | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String[] | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : String | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:21:114:66 | (...) ... : String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] | -| GlobalDataFlow.cs:114:57:114:64 | access to local variable nonSink0 : T | GlobalDataFlow.cs:114:42:114:66 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : IEnumerable | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:76:114:76 | x | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:76:114:76 | x : String | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:81:114:81 | access to parameter x | -| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:9:114:82 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:114:20:114:82 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | GlobalDataFlow.cs:115:15:115:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:116:57:116:70 | call to method First : String | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:116:57:116:62 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:21:116:72 | (...) ... : String[] | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] | -| GlobalDataFlow.cs:116:57:116:70 | call to method First : String | GlobalDataFlow.cs:116:42:116:72 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String[] | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:80:116:119 | (...) ... : String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] | -| GlobalDataFlow.cs:116:116:116:117 | "" : String | GlobalDataFlow.cs:116:101:116:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:9:116:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:20:116:134 | call to method Zip | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:116:20:116:134 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | GlobalDataFlow.cs:117:15:117:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : IEnumerable | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:127:116:127 | y | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:127:116:127 | y : String | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:133:116:133 | access to parameter y | -| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... | -| GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String | GlobalDataFlow.cs:116:123:116:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String[] | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:21:118:60 | (...) ... : String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] | -| GlobalDataFlow.cs:118:57:118:58 | "" : String | GlobalDataFlow.cs:118:42:118:60 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First | -| GlobalDataFlow.cs:118:104:118:109 | access to local variable sink15 : IEnumerable | GlobalDataFlow.cs:118:104:118:117 | call to method First : String | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:68:118:119 | (...) ... : String[] | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] | -| GlobalDataFlow.cs:118:104:118:117 | call to method First : String | GlobalDataFlow.cs:118:89:118:119 | array creation of type String[] : String[] | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:9:118:134 | SSA def(nonSink1) : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:20:118:134 | call to method Zip | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:118:20:118:134 | call to method Zip : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : IEnumerable | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:124:118:124 | x | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:124:118:124 | x : String | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:133:118:133 | access to parameter x | -| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... | -| GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String | GlobalDataFlow.cs:118:123:118:133 | [output] (...) => ... : String | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 | -| GlobalDataFlow.cs:119:15:119:22 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 | -| GlobalDataFlow.cs:120:20:120:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:37:120:38 | "" : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : Object | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:42:120:44 | acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:42:120:44 | acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:42:120:44 | acc : String | GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... | -| GlobalDataFlow.cs:120:53:120:55 | access to parameter acc : String | GlobalDataFlow.cs:120:41:120:55 | [output] (...) => ... : String | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : Object | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:58:120:58 | x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:58:120:58 | x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:58 | x : String | GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:9:120:64 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:120:20:120:64 | call to method Aggregate : String | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | GlobalDataFlow.cs:121:15:121:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... | -| GlobalDataFlow.cs:120:63:120:63 | access to parameter x : String | GlobalDataFlow.cs:120:58:120:63 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:20:122:25 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:37:122:38 | "" : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:42:122:44 | acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:42:122:44 | acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:42:122:44 | acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:47:122:47 | s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : IEnumerable | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:47:122:47 | s | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:47:122:47 | s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : Object | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:47:122:47 | s : String | GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:53:122:55 | access to parameter acc : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... | -| GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | GlobalDataFlow.cs:122:41:122:59 | [output] (...) => ... : String | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:59:122:59 | access to parameter s : String | GlobalDataFlow.cs:122:53:122:59 | ... + ... : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:9:122:69 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:122:20:122:69 | call to method Aggregate : String | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | GlobalDataFlow.cs:123:15:123:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... | -| GlobalDataFlow.cs:122:67:122:68 | "" : String | GlobalDataFlow.cs:122:62:122:68 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:20:124:27 | access to local variable nonSink1 : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:52:124:52 | s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : IEnumerable | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:52:124:52 | s | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:52:124:52 | s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : Object | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:52:124:52 | s : String | GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... | -| GlobalDataFlow.cs:124:58:124:58 | access to parameter s : String | GlobalDataFlow.cs:124:46:124:58 | [output] (...) => ... : String | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : Object | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:61:124:61 | x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:61:124:61 | x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:61 | x : String | GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:9:124:67 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:124:20:124:67 | call to method Aggregate : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... | -| GlobalDataFlow.cs:124:66:124:66 | access to parameter x : String | GlobalDataFlow.cs:124:61:124:66 | [output] (...) => ... : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:125:15:125:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:127:24:127:31 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 | -| GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) : Int32 | GlobalDataFlow.cs:128:15:128:22 | access to local variable nonSink2 : Int32 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 | -| GlobalDataFlow.cs:130:23:130:30 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 | -| GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) : Boolean | GlobalDataFlow.cs:131:15:131:22 | access to local variable nonSink3 : Boolean | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | -| GlobalDataFlow.cs:134:40:134:40 | x : Object | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : String | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x | -| GlobalDataFlow.cs:134:40:134:40 | x : T | GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:134:30:134:64 | SSA def(return) : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:134:40:134:64 | (...) => ... : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | GlobalDataFlow.cs:139:20:139:36 | delegate call : T | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:134:55:134:60 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:134:63:134:63 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return | -| GlobalDataFlow.cs:135:21:135:27 | access to local variable return : Func | GlobalDataFlow.cs:139:20:139:26 | access to local variable return : Func | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : 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:136:15:136:19 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | 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:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:135:13:135:34 | SSA def(sink4) : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:134:40:134:40 | x : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : Object | GlobalDataFlow.cs:135:21:135:34 | delegate call : Object | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:134:40:134:40 | x : T | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : T | GlobalDataFlow.cs:135:21:135:34 | delegate call : T | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 : T | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : String | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:139:9:139:36 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:139:20:139:36 | delegate call : T | GlobalDataFlow.cs:140:15:140:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:134:40:134:40 | x : String | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:139:28:139:35 | access to local variable nonSink0 : String | GlobalDataFlow.cs:139:20:139:36 | delegate call : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : 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:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:143:13:143:44 | SSA def(sink5) : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:143:31:143:36 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| 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:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : Object | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : String | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 : T | GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:147:9:147:40 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | GlobalDataFlow.cs:148:15:148:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:147:30:147:35 | delegate creation of type Func : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:147:38:147:39 | "" : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:149:9:149:44 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:149:30:149:36 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:149:35:149:36 | "" : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:149:39:149:43 | access to local variable sink5 : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 | -| GlobalDataFlow.cs:150:15:150:22 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:153:13:153:25 | SSA def(sink6) : 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:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 : String | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this | -| GlobalDataFlow.cs:153:21:153:25 | this access : DataFlow | GlobalDataFlow.cs:316:12:316:14 | this : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this | -| GlobalDataFlow.cs:156:9:156:25 | this access : DataFlow | GlobalDataFlow.cs:321:10:321:15 | this : DataFlow | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 : String | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:158:13:158:22 | SSA def(sink8) : String | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 | -| GlobalDataFlow.cs:158:21:158:22 | "" : String | GlobalDataFlow.cs:159:20:159:24 | access to local variable sink8 : String | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this | -| GlobalDataFlow.cs:159:9:159:25 | this access : DataFlow | GlobalDataFlow.cs:326:10:326:15 | this : DataFlow | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 : String | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:161:13:161:31 | SSA def(sink12) : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 : IEnumerable | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this | -| GlobalDataFlow.cs:161:22:161:31 | this access : DataFlow | GlobalDataFlow.cs:331:25:331:32 | this : DataFlow | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : String | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:163:13:163:43 | SSA def(sink23) : T | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : String | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : T | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:163:35:163:42 | access to local variable nonSink0 : T | GlobalDataFlow.cs:378:39:378:45 | tainted : T | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:167:9:167:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | GlobalDataFlow.cs:168:15:168:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this | -| GlobalDataFlow.cs:167:20:167:27 | this access : DataFlow | GlobalDataFlow.cs:338:12:338:17 | this : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this | -| GlobalDataFlow.cs:169:9:169:31 | this access : DataFlow | GlobalDataFlow.cs:343:10:343:18 | this : DataFlow | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 | -| GlobalDataFlow.cs:170:15:170:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:171:23:171:30 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this | -| GlobalDataFlow.cs:171:9:171:31 | this access : DataFlow | GlobalDataFlow.cs:348:10:348:18 | this : DataFlow | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | GlobalDataFlow.cs:172:15:172:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:20:173:40 | call to method First | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:173:20:173:40 | call to method First : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this | -| GlobalDataFlow.cs:173:20:173:32 | this access : DataFlow | GlobalDataFlow.cs:353:25:353:35 | this : DataFlow | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:173:9:173:40 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:173:20:173:40 | call to method First : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 | -| GlobalDataFlow.cs:174:15:174:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:175:9:175:44 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | GlobalDataFlow.cs:176:15:176:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:175:36:175:43 | access to local variable nonSink0 : String | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:179:22:179:48 | SSA def(out) : Func | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out | -| GlobalDataFlow.cs:179:29:179:48 | (...) => ... : Func | GlobalDataFlow.cs:180:21:180:24 | access to local variable out : Func | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:180:13:180:26 | SSA def(sink9) : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 : String | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:184:22:184:38 | SSA def(nonOut) : Func | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut | -| GlobalDataFlow.cs:184:31:184:38 | (...) => ... : Func | GlobalDataFlow.cs:185:20:185:25 | access to local variable nonOut : Func | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:184:37:184:38 | "" : String | GlobalDataFlow.cs:185:20:185:27 | delegate call : String | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:185:9:185:27 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:185:20:185:27 | delegate call : String | GlobalDataFlow.cs:186:15:186:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : Lazy | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : Lazy | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : 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:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:13:189:48 | SSA def(sink10) : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : 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:190:15:190:20 | access to local variable sink10 : String | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:189:39:189:41 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : Lazy | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy : Lazy | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : Lazy | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:9:193:49 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:193:20:193:49 | access to property Value : String | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:194:15:194:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:193:37:193:42 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:197:13:197:32 | SSA def(sink19) : 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:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 : String | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this | -| GlobalDataFlow.cs:197:22:197:32 | this access : DataFlow | GlobalDataFlow.cs:415:9:415:11 | this : DataFlow | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | GlobalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this | -| GlobalDataFlow.cs:201:20:201:33 | this access : DataFlow | GlobalDataFlow.cs:420:9:420:11 | this : DataFlow | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:205:39:205:45 | tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:205:39:205:45 | tainted : Object | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:205:67:205:76 | notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:205:67:205:76 | notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:205:67:205:76 | notTainted : Object | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : Object | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:208:30:208:92 | SSA def(f1) : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:208:35:208:92 | (...) => ... : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:208:79:208:89 | access to parameter sinkParam10 : String | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:71:209:71 | x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : Object | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:71 | x : String | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:209:66:209:90 | SSA def(f2) : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:209:71:209:90 | (...) => ... : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:13:210:39 | SSA def(sink24) : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:22:210:39 | call to method Select | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:210:22:210:39 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 : IEnumerable | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 | -| GlobalDataFlow.cs:210:37:210:38 | access to local variable f1 : Func | GlobalDataFlow.cs:220:41:220:42 | access to local variable f1 : Func | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:13:212:39 | SSA def(sink25) : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:212:22:212:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 | -| GlobalDataFlow.cs:212:37:212:38 | access to local variable f2 : Expression> | GlobalDataFlow.cs:222:37:222:38 | access to local variable f2 : Expression> | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:13:214:49 | SSA def(sink26) : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:22:214:49 | call to method Select | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:214:22:214:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 : IEnumerable | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : Object | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:218:30:218:95 | SSA def(f3) : Func | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 | -| GlobalDataFlow.cs:218:35:218:95 | (...) => ... : Func | GlobalDataFlow.cs:224:37:224:38 | access to local variable f3 : Func | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:59:218:70 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:218:81:218:92 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:71:219:71 | x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : Object | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:71 | x : String | GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:219:66:219:92 | SSA def(f4) : Expression> | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 | -| GlobalDataFlow.cs:219:71:219:92 | (...) => ... : Expression> | GlobalDataFlow.cs:226:37:226:38 | access to local variable f4 : Expression> | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:219:91:219:91 | access to parameter x : String | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:220:23:220:32 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:13:220:43 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:23:220:43 | call to method Select | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:220:23:220:43 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink | -| GlobalDataFlow.cs:220:41:220:42 | [output] access to local variable f1 : String | GlobalDataFlow.cs:221:15:221:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:222:19:222:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:9:222:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:222:19:222:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink | -| GlobalDataFlow.cs:222:37:222:38 | [output] access to local variable f2 : T | GlobalDataFlow.cs:223:15:223:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:218:35:218:46 | nonSinkParam : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:224:19:224:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:9:224:39 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:224:19:224:39 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink | -| GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f3 : String | GlobalDataFlow.cs:225:15:225:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:219:71:219:71 | x : IQueryable | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted | -| GlobalDataFlow.cs:226:19:226:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : String | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:9:226:39 | SSA def(nonSink) : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:226:19:226:39 | call to method Select : IQueryable | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink | -| GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f4 : T | GlobalDataFlow.cs:227:15:227:21 | access to local variable nonSink : IQueryable | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:228:19:228:28 | access to parameter notTainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:9:228:49 | SSA def(nonSink) : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:19:228:49 | call to method Select | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:228:19:228:49 | call to method Select : IEnumerable | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink | -| GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:229:15:229:21 | access to local variable nonSink : IEnumerable | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : Object | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : T | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : Object | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : T | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : Object | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : String | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : Object | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : String | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : T | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : Object | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : String | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : T | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : Object | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : String | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : T | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : Object | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : String | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : T | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : Object | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : String | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : String | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 | -| GlobalDataFlow.cs:270:29:270:41 | nonSinkParam0 : T | GlobalDataFlow.cs:272:15:272:27 | access to parameter nonSinkParam0 : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | -| GlobalDataFlow.cs:275:26:275:26 | x : Object | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : String | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:275:26:275:26 | x : T | GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:277:13:277:38 | SSA def(y) : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : Object | -| GlobalDataFlow.cs:277:27:277:28 | x0 : Object | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : String | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : String | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:28 | x0 : T | GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:277:27:277:34 | (...) => ... : Func | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:277:33:277:34 | access to parameter x0 : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : Object | GlobalDataFlow.cs:364:46:364:46 | x : Object | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : String | GlobalDataFlow.cs:364:46:364:46 | x : String | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:277:37:277:37 | access to parameter x : T | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | GlobalDataFlow.cs:278:16:278:24 | ... == ... : Boolean | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:16 | (...) ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : Object | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:16 | (...) ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : String | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:16 | (...) ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:16 | access to local variable y : T | GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:70:21:70:46 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:100:24:100:33 | call to method Return : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke : T | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:28:278:37 | default(...) : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : Object | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : Object | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : String | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : String | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:278:41:278:41 | access to local variable y : T | GlobalDataFlow.cs:278:16:278:41 | ... ? ... : ... : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:281:32:281:32 | x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:281:32:281:32 | x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | -| GlobalDataFlow.cs:281:32:281:32 | x : Object | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : String | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:281:32:281:32 | x : T | GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : T | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : Object | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : String | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : String | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:283:13:283:13 | access to parameter x : T | GlobalDataFlow.cs:283:9:283:13 | SSA def(y) : T | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) | -| GlobalDataFlow.cs:284:13:284:22 | default(...) : T | GlobalDataFlow.cs:284:9:284:22 | SSA def(z) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:287:32:287:32 | x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:287:32:287:32 | x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | -| GlobalDataFlow.cs:287:32:287:32 | x : Object | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : String | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:32:287:32 | x : T | GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | -| GlobalDataFlow.cs:287:50:287:50 | z : Object | GlobalDataFlow.cs:287:50:287:50 | z | -| GlobalDataFlow.cs:287:50:287:50 | z : Object | GlobalDataFlow.cs:287:50:287:50 | z : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) : T | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : Object | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : Object | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : String | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : String | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:289:13:289:13 | access to parameter x : T | GlobalDataFlow.cs:289:9:289:13 | SSA def(y) : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : IEnumerable | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : Object | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : Object | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : String | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:301:16:301:25 | access to parameter sinkParam9 : T | GlobalDataFlow.cs:209:76:209:90 | call to method ReturnCheck2 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : Object | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:307:16:307:26 | access to parameter sinkParam11 : T | GlobalDataFlow.cs:228:37:228:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : Object | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:310:34:310:45 | nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : String | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : String | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam | -| GlobalDataFlow.cs:312:15:312:26 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:313:16:313:27 | access to parameter nonSinkParam : T | GlobalDataFlow.cs:219:76:219:92 | call to method NonReturnCheck : T | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:333:22:333:23 | "" : String | GlobalDataFlow.cs:333:22:333:23 | "" | -| GlobalDataFlow.cs:333:22:333:23 | "" : String | GlobalDataFlow.cs:333:22:333:23 | "" : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:335:22:335:23 | "" : String | GlobalDataFlow.cs:335:22:335:23 | "" | -| GlobalDataFlow.cs:335:22:335:23 | "" : String | GlobalDataFlow.cs:335:22:335:23 | "" : IEnumerable | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut : String | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func | -| GlobalDataFlow.cs:340:16:340:17 | "" : String | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) | -| GlobalDataFlow.cs:345:13:345:14 | "" : String | GlobalDataFlow.cs:345:9:345:14 | SSA def(x) : String | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) | -| GlobalDataFlow.cs:350:13:350:14 | "" : String | GlobalDataFlow.cs:350:9:350:14 | SSA def(x) : String | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:355:22:355:23 | "" : String | GlobalDataFlow.cs:355:22:355:23 | "" | -| GlobalDataFlow.cs:355:22:355:23 | "" : String | GlobalDataFlow.cs:355:22:355:23 | "" : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield : IEnumerable | -| GlobalDataFlow.cs:356:22:356:23 | "" : String | GlobalDataFlow.cs:356:22:356:23 | "" | -| GlobalDataFlow.cs:356:22:356:23 | "" : String | GlobalDataFlow.cs:356:22:356:23 | "" : IEnumerable | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Action | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:359:36:359:36 | a | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:359:36:359:36 | a : Action | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:361:9:361:9 | access to parameter a | -| GlobalDataFlow.cs:359:36:359:36 | a : Object | GlobalDataFlow.cs:361:9:361:9 | access to parameter a : Action | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:359:41:359:41 | x | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:359:41:359:41 | x : T | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : Object | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x | -| GlobalDataFlow.cs:359:41:359:41 | x : T | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:53:15:53:15 | x : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:60:15:60:27 | nonSinkParam0 : T | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : T | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : T | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Func | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:364:41:364:41 | f | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:364:41:364:41 | f : Func | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:366:16:366:16 | access to parameter f | -| GlobalDataFlow.cs:364:41:364:41 | f : Object | GlobalDataFlow.cs:366:16:366:16 | access to parameter f : Func | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:364:46:364:46 | x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:364:46:364:46 | x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | -| GlobalDataFlow.cs:364:46:364:46 | x : Object | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : String | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:364:46:364:46 | x : T | GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : String | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:16:366:19 | delegate call : T | GlobalDataFlow.cs:277:17:277:38 | call to method ApplyFunc : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:275:26:275:26 | x : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:277:27:277:28 | x0 : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : Object | GlobalDataFlow.cs:366:16:366:19 | delegate call : Object | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:275:26:275:26 | x : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:277:27:277:28 | x0 : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : String | GlobalDataFlow.cs:366:16:366:19 | delegate call : String | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:275:26:275:26 | x : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:277:27:277:28 | x0 : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:366:18:366:18 | access to parameter x : T | GlobalDataFlow.cs:366:16:366:19 | delegate call : T | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:373:42:373:42 | a | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:373:42:373:42 | a : MyDelegate | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:375:9:375:9 | access to parameter a | -| GlobalDataFlow.cs:373:42:373:42 | a : Object | GlobalDataFlow.cs:375:9:375:9 | access to parameter a : MyDelegate | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:373:52:373:52 | x | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:373:52:373:52 | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : Object | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:61:38:61:50 | nonSinkParam0 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:378:39:378:45 | tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:378:39:378:45 | tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : Object | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:380:13:380:28 | SSA def(sink11) : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:380:22:380:28 | access to parameter tainted : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 : T | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : T | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:385:42:385:51 | nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : Object | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:385:42:385:51 | nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:387:13:387:33 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:387:24:387:33 | access to parameter nonTainted : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 : String | GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:389:16:389:23 | access to local variable nonSink0 : String | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam : String | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:398:62:398:63 | "" : String | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:9:404:11 | value | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:9:404:11 | value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : Object | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:19:404:32 | SSA def(sink20) : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:404:28:404:32 | access to parameter value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:9:410:11 | value | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:9:410:11 | value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : Object | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:9:410:11 | value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:19:410:34 | SSA def(nonSink0) : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:410:30:410:34 | access to parameter value : String | GlobalDataFlow.cs:410:43:410:50 | access to local variable nonSink0 : String | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:420:22:420:23 | "" : String | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty : String | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:426:71:426:71 | e | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:426:71:426:71 | e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : Object | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:71:426:71 | e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Func | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:426:85:426:85 | f | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:426:85:426:85 | f : Func | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:431:44:431:44 | access to parameter f | -| GlobalDataFlow.cs:426:85:426:85 | f : Object | GlobalDataFlow.cs:431:44:431:44 | access to parameter f : Func | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:428:13:428:17 | SSA def(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:428:17:428:17 | 0 : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : IEnumerable | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:429:27:429:27 | access to parameter e : String[] | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:429:9:432:9 | SSA phi(i) : Int32 | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i | -| GlobalDataFlow.cs:431:17:431:19 | SSA def(i) : Int32 | GlobalDataFlow.cs:431:17:431:17 | access to local variable i : Int32 | -| GlobalDataFlow.cs:431:17:431:23 | ... % ... : Int32 | GlobalDataFlow.cs:431:17:431:28 | ... == ... | -| GlobalDataFlow.cs:431:17:431:23 | ... % ... : Int32 | GlobalDataFlow.cs:431:17:431:28 | ... == ... : Boolean | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | GlobalDataFlow.cs:112:24:112:90 | call to method SelectEven : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : String | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:3:18:3:18 | b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:3:18:3:18 | b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:5:13:5:13 | access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:5:13:5:13 | access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:3:18:3:18 | b : Object | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:3:28:3:34 | tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:3:28:3:34 | tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : Object | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | -| 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 | -| 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:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): false] access to parameter b : Boolean | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b | -| Splitting.cs:5:13:5:13 | access to parameter b : Boolean | Splitting.cs:10:13:10:13 | [b (line 3): true] access to parameter b : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:6:17:6:31 | [b (line 3): true] ... == ... : Boolean | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | -| Splitting.cs:6:17:6:23 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : 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 | -| 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 : String | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): false] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:8:13:8:31 | [b (line 3): true] SSA def(x) : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : 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): true] call to method Return | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : String | Splitting.cs:11:19:11:19 | access to local variable x : String | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x | -| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x : T | Splitting.cs:11:19:11:19 | access to local variable x : T | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:26:16:26 | x : T | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : Object | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : String | Splitting.cs:16:32:16:32 | access to parameter x : String | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x | -| Splitting.cs:16:26:16:26 | x : T | Splitting.cs:16:32:16:32 | access to parameter x : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:20:22:20:30 | call to method Return : T | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:16:32:16:32 | access to parameter x : T | Splitting.cs:21:21:21:33 | call to method Return : T | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : Object | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:18:24:18:24 | s : String | Splitting.cs:20:29:20:29 | access to parameter s : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:20:22:20:30 | call to method Return : T | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:20:29:20:29 | access to parameter s : String | Splitting.cs:20:22:20:30 | call to method Return : String | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:9:21:11 | value | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:9:21:11 | value : String | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : Object | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:9:21:11 | value : String | Splitting.cs:21:28:21:32 | access to parameter value : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:16:26:16:26 | x : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:21:28:21:32 | access to parameter value : String | Splitting.cs:21:21:21:33 | call to method Return : String | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:24:10:24:11 | this : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:24:18:24:18 | b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:24:18:24:18 | b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:26:13:26:13 | access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:26:13:26:13 | access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:24:18:24:18 | b : Object | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:24:28:24:34 | tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:24:28:24:34 | tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| 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:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| 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 | -| 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): false] access to local variable x : Object | -| 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:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:24:28:24:34 | tainted : String | 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 : Object | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): false] access to parameter b : Boolean | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b | -| Splitting.cs:26:13:26:13 | access to parameter b : Boolean | Splitting.cs:33:13:33:13 | [b (line 24): true] access to parameter b : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:27:17:27:31 | [b (line 24): true] ... == ... : Boolean | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:27:17:27:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): false] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): false] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:29:17:29:24 | [b (line 24): true] SSA def(d) : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:29:21:29:24 | [b (line 24): true] this access : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:21:9:21:11 | this : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:21:9:21:11 | this : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| 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): false] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value | -| 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:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:9 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:30:9:30:13 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): false] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:20:9:20:11 | this : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:20:9:20:11 | this : Splitting | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:17 | [b (line 24): true] access to local variable d : Splitting | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : 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 | -| 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 : String | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): false] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:31:13:31:26 | [b (line 24): true] SSA def(x) : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element | -| Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s | -| Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:18:24:18:24 | s : String | -| 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 | -| 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 | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : Object | Splitting.cs:34:19:34:19 | access to local variable x : Object | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : String | Splitting.cs:34:19:34:19 | access to local variable x : String | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x | -| Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x : T | Splitting.cs:34:19:34:19 | access to local variable x : T | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:11:13:11:16 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:11:13:11:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:9:12:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:12:16:12:19 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:9:13:15 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:13:11:13:14 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:15:9:15:12 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:20:9:20 | this : This | This.cs:16:9:16:16 | this access : This | -| This.cs:9:27:9:31 | other : Object | This.cs:9:27:9:31 | other | -| This.cs:9:27:9:31 | other : Object | This.cs:9:27:9:31 | other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Object | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Object | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:14:13:14:17 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:14:13:14:17 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:9:27:9:31 | other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:9:12:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:9:12:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:11:13:11:16 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:12:16:12:19 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:12:16:12:19 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:9:12:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:9:13:15 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:9:13:15 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:12:16:12:19 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:13:11:13:14 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:13:11:13:14 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:9:13:15 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:15:9:15:12 | this access : Sub | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:15:9:15:12 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:13:11:13:14 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:15:16:15:20 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:15:16:15:20 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:14:13:14:17 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : Sub | This.cs:16:9:16:16 | this access : Sub | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:9:15:12 | this access : This | This.cs:16:9:16:16 | this access : This | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : Sub | This.cs:16:11:16:15 | access to parameter other : Sub | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:15:16:15:20 | access to parameter other : This | This.cs:16:11:16:15 | access to parameter other : This | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:9:16:16 | this access : This | This.cs:9:20:9:20 | this : This | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:16:11:16:15 | access to parameter other : This | This.cs:9:27:9:31 | other : This | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this | -| This.cs:17:9:17:18 | malloc : This | This.cs:7:5:7:8 | this : This | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:13:26:16 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access | -| This.cs:24:14:24:15 | this : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this | -| This.cs:26:13:26:16 | this access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:26:20:26:23 | this access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:13:26:16 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:26:20:26:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:13:27:16 | base access : Sub | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:26:20:26:23 | this access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : Sub | This.cs:9:20:9:20 | this : Sub | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : Sub | This.cs:27:20:27:23 | this access : Sub | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this | -| This.cs:27:13:27:16 | base access : This | This.cs:9:20:9:20 | this : This | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access | -| This.cs:27:13:27:16 | base access : This | This.cs:27:20:27:23 | this access : This | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : Sub | This.cs:9:27:9:31 | other : Sub | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other | -| This.cs:27:20:27:23 | this access : This | This.cs:9:27:9:31 | other : This | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this | -| This.cs:28:13:28:21 | malloc : Sub | This.cs:22:9:22:11 | this : Sub | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql deleted file mode 100644 index 163130bea8f..00000000000 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingEdges.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp -import DataFlow -import semmle.code.csharp.dataflow.internal.DataFlowPrivate - -class ConfigAny extends TaintTracking::Configuration { - ConfigAny() { this = "ConfigAny" } - - override predicate isSource(Node source) { - source instanceof PostUpdateNode implies source.asExpr() instanceof ObjectCreation - } - - override predicate isSink(Node sink) { - sink instanceof PostUpdateNode implies sink.asExpr() instanceof ObjectCreation - } -} - -query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b } diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index c612897d3ee..7e5184651c9 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -1,46 +1,26 @@ 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 | @@ -75,7 +55,7 @@ edges | 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:234:26:234:35 | sinkParam0 : 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 | @@ -84,7 +64,7 @@ edges | 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:240:26:240:35 | sinkParam1 : 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 | @@ -100,31 +80,31 @@ edges | 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:359:41:359:41 | x : 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:250:26:250:35 | sinkParam4 : 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:359:41:359:41 | x : 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:373:52:373:52 | x : 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:373:52:373:52 | x : 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:265:26:265:35 | sinkParam7 : 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:373:52:373:52 | x : 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:404:9:404:11 | value : 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 | @@ -140,27 +120,19 @@ edges | 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:74 | (...) ... : String[] | +| 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:74 | (...) ... : String[] | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:82:23:82:74 | (...) ... : String[] | GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:90:75:90:88 | call to method First : String | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:112:90:117 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | | 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 | @@ -173,58 +145,52 @@ edges | 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:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| 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:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:211:71:211:71 | x : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : 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: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:22:189:42 | object creation of type Lazy [Value] : 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:22:336:35 | "taint source" : String | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : 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 | | 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 | @@ -249,50 +215,30 @@ 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 | @@ -333,22 +279,14 @@ nodes | 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:74 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84:74 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:84:125:84:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:86:70:86:121 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:86:125:86:135 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | -| GlobalDataFlow.cs:88:22:88:27 | access to local variable sink14 : IEnumerable | semmle.label | access to local variable sink14 : IEnumerable | -| GlobalDataFlow.cs:88:43:88:61 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:64:88:69 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:75:90:88 | call to method First : String | semmle.label | call to method First : String | -| GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:112:90:117 | [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 | @@ -371,68 +309,62 @@ nodes | 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:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : 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: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:205:39:205:45 | tainted : IQueryable | semmle.label | tainted : IQueryable | -| GlobalDataFlow.cs:208:35:208:45 | sinkParam10 : IQueryable | semmle.label | sinkParam10 : IQueryable | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:209:71:209:71 | x : IQueryable | semmle.label | x : IQueryable | -| GlobalDataFlow.cs:209:89:209:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:210:22:210:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:210:37:210:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:212:22:212:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:214:22:214:28 | access to parameter tainted : IQueryable | semmle.label | access to parameter tainted : IQueryable | -| GlobalDataFlow.cs:214:37:214:48 | [output] delegate creation of type Func : T | semmle.label | [output] delegate creation of type Func : T | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:234:26:234:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:236:16:236:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:240:26:240:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:245:26:245:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:250:26:250:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:255:26:255:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:260:26:260:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:265:26:265:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | semmle.label | sinkParam8 : String[] | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | -| GlobalDataFlow.cs:298:32:298:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:304:32:304:42 | sinkParam11 : IQueryable | semmle.label | sinkParam11 : IQueryable | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | -| GlobalDataFlow.cs:318:16:318:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:323:9:323:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:323:13:323:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:328:9:328:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:328:13:328:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : IEnumerable | semmle.label | "taint source" : IEnumerable | -| GlobalDataFlow.cs:334:22:334:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:359:41:359:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:361:11:361:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:373:52:373:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:11:375:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:378:39:378:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:382:16:382:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:404:9:404:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:415:22:415:35 | "taint source" : String | semmle.label | "taint source" : String | +| 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:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| 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: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 | | 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 | @@ -485,30 +417,30 @@ nodes | 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:318:16:318: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:323:13:323: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:328:13:328: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:334:22:334: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:378:39:378:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| 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:318:16:318: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:415:22:415:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:208:58:208:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink24 | access to local variable sink24 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink25 | access to local variable sink25 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink26 | access to local variable sink26 | -| GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:237:15:237:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:242:15:242:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:247:15:247:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:252:15:252:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:257:15:257:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:262:15:262:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:267:15:267:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:300:15:300:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:205:39:205:45 | tainted : IQueryable | GlobalDataFlow.cs:306:15:306:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | GlobalDataFlow.cs:378:39:378:45 | tainted : String | GlobalDataFlow.cs:381:15:381:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:404:41:404:46 | access to local variable sink20 | access to local variable sink20 | +| 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 | | 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.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 6631539ed2d..6769e2a1411 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1,3 +1,4 @@ +callableFlow | LibraryTypeDataFlow.DataContract.get_AString() | qualifier -> return | false | | System.Array.Add(object) | argument 0 -> qualifier | false | | System.Array.AsReadOnly(T[]) | qualifier -> return | false | @@ -661,10 +662,6 @@ | 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.Lazy<>.Lazy(Func) | output from argument 0 -> return | true | -| System.Lazy<>.Lazy(Func, LazyThreadSafetyMode) | output from argument 0 -> return | true | -| System.Lazy<>.Lazy(Func, bool) | output from argument 0 -> return | true | -| System.Lazy<>.get_Value() | qualifier -> return | true | | 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 | @@ -1139,6 +1136,8 @@ | 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 | @@ -1684,3 +1683,7 @@ | System.Web.HttpUtility.HtmlEncode(string) | argument 0 -> return | false | | 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] | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql index 2c050ebd399..a5d65c711a3 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql @@ -1,22 +1,27 @@ import semmle.code.csharp.dataflow.LibraryTypeDataFlow -predicate callableFlow(string callable, string flow, boolean preservesValue) { +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.toString() + " -> " + sink.toString() + 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)" ) } -from string entity, string flow, boolean preservesValue -where - callableFlow(entity, flow, preservesValue) and - /* - * Remove certain results to make the test output consistent - * between different versions of .NET Core. - */ - - not entity = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" -select entity, flow, preservesValue +query predicate callableFlowAccessPath(string callable, string flow) { + 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 + callable = c.getQualifiedNameWithTypes() and + flow = source + " [" + sourceAp + "] -> " + sink + " [" + sinkAp + "]" + ) +} diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index 78c0204ed20..e9a03e58b0a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,16 +1,12 @@ | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| 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 | | 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 658dc392eee..f641a355f83 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -24,8 +24,7 @@ | 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:23:49:23 | this | LocalDataFlow.cs:299:39:299:51 | this access | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | +| 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 | @@ -38,567 +37,402 @@ | 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:204:20:204:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | 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:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:69:21:69:51 | object creation of type Dictionary | LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | -| LocalDataFlow.cs:70:9:70:13 | [post] access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | -| LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:74:24:74:55 | object creation of type Dictionary | LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | -| LocalDataFlow.cs:75:9:75:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | [post] access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:76:9:76:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:18:76:22 | [post] access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | -| LocalDataFlow.cs:80:21:80:32 | ... + ... | LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | -| LocalDataFlow.cs:81:15:81:19 | [post] access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:84:20:84:36 | ... + ... | LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:15:85:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | [post] access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:101:15:101:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | -| LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | LocalDataFlow.cs:104:21:104:33 | (...) ... | -| LocalDataFlow.cs:105:15:105:19 | [post] access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | LocalDataFlow.cs:109:15:109:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:108:24:108:39 | (...) ... | LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:108:24:108:39 | (...) ... | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:35 | ... as ... | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | -| LocalDataFlow.cs:112:21:112:35 | ... as ... | LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | -| LocalDataFlow.cs:113:15:113:19 | [post] access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | LocalDataFlow.cs:117:15:117:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:37 | ... as ... | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:20:116:37 | ... as ... | LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | [post] access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | -| LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | -| LocalDataFlow.cs:124:39:124:40 | 42 | LocalDataFlow.cs:124:39:124:40 | (...) ... | -| LocalDataFlow.cs:125:15:125:22 | [post] access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | -| LocalDataFlow.cs:128:61:128:65 | [post] access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | -| LocalDataFlow.cs:132:55:132:59 | [post] access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:133:15:133:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:136:22:136:27 | [post] access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:55 | call to method First | LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:40:136:40 | access to parameter x | -| LocalDataFlow.cs:136:40:136:40 | access to parameter x | LocalDataFlow.cs:136:40:136:46 | access to property Value | -| LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | LocalDataFlow.cs:206:33:206:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:55 | (...) ... | LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | -| LocalDataFlow.cs:140:20:140:55 | call to method First | LocalDataFlow.cs:140:20:140:55 | (...) ... | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:40:140:40 | access to parameter x | -| LocalDataFlow.cs:140:40:140:40 | access to parameter x | LocalDataFlow.cs:140:40:140:46 | access to property Value | -| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:144:22:144:39 | call to method Parse | LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | -| LocalDataFlow.cs:144:34:144:38 | [post] access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | -| LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:147:22:147:56 | call to method TryParse | LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | -| LocalDataFlow.cs:147:37:147:41 | [post] access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:149:22:149:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:49 | call to method Replace | LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | -| LocalDataFlow.cs:149:44:149:48 | [post] access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:151:22:151:51 | call to method Format | LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | -| LocalDataFlow.cs:151:36:151:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:46:151:50 | [post] access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:152:15:152:20 | [post] access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:153:22:153:52 | call to method Format | LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | -| LocalDataFlow.cs:153:44:153:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:155:22:155:38 | call to method Parse | LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | -| LocalDataFlow.cs:155:33:155:37 | [post] access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:158:22:158:56 | call to method TryParse | LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | -| LocalDataFlow.cs:158:36:158:40 | [post] access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | -| LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:160:22:160:43 | call to method ToByte | LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | -| LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:162:22:162:46 | call to method Concat | LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | -| LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | (...) ... | -| LocalDataFlow.cs:163:15:163:20 | [post] access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:164:22:164:40 | call to method Copy | LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | -| LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | LocalDataFlow.cs:164:22:164:40 | call to method Copy | -| LocalDataFlow.cs:165:15:165:20 | [post] access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:166:22:166:54 | call to method Join | LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | -| LocalDataFlow.cs:167:15:167:20 | [post] access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:168:22:168:41 | call to method Insert | LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | -| LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | LocalDataFlow.cs:173:15:173:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:172:20:172:40 | call to method Parse | LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:172:32:172:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | LocalDataFlow.cs:175:15:175:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:174:24:174:61 | call to method TryParse | LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:174:39:174:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:50 | call to method Replace | LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:177:15:177:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:20:178:52 | call to method Format | LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:178:34:178:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | LocalDataFlow.cs:181:15:181:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:180:20:180:39 | call to method Parse | LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:180:31:180:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:182:20:182:57 | call to method TryParse | LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | LocalDataFlow.cs:185:15:185:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:184:25:184:48 | call to method ToByte | LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:186:20:186:46 | call to method Concat | LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | (...) ... | -| LocalDataFlow.cs:187:15:187:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:20:188:40 | call to method Copy | LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | LocalDataFlow.cs:188:20:188:40 | call to method Copy | -| LocalDataFlow.cs:189:15:189:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:20:190:54 | call to method Join | LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:191:15:191:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | LocalDataFlow.cs:193:15:193:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:20:192:41 | call to method Insert | LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:196:22:196:32 | ... > ... | LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | -| LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:198:22:198:40 | call to method Equals | LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | -| LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:200:22:200:26 | [post] access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:45 | call to method Equals | LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | -| LocalDataFlow.cs:200:43:200:44 | 41 | LocalDataFlow.cs:200:35:200:44 | (...) ... | -| LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | LocalDataFlow.cs:205:15:205:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:204:20:204:24 | [post] access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:38 | call to method Equals | LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:204:33:204:37 | [post] access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:206:20:206:41 | call to method Equals | LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:210:22:210:31 | access to indexer | LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | -| LocalDataFlow.cs:211:15:211:20 | [post] access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:214:20:214:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:31 | access to indexer | LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | -| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | -| LocalDataFlow.cs:218:22:218:30 | access to array element | LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | -| LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | LocalDataFlow.cs:223:15:223:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | -| LocalDataFlow.cs:222:20:222:30 | access to array element | LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | -| LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | -| LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | LocalDataFlow.cs:231:15:231:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | -| LocalDataFlow.cs:235:15:235:20 | [post] access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:236:22:236:27 | [post] access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:38 | call to method ToString | LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | -| LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:238:22:238:27 | [post] access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | -| LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:240:22:240:27 | [post] access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:33 | access to property Query | LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | -| LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | -| LocalDataFlow.cs:243:15:243:20 | [post] access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:247:15:247:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | LocalDataFlow.cs:249:15:249:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:248:20:248:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:38 | call to method ToString | LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | LocalDataFlow.cs:251:15:251:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:250:20:250:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | LocalDataFlow.cs:253:15:253:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:252:20:252:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:33 | access to property Query | LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:255:15:255:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | -| LocalDataFlow.cs:259:15:259:20 | [post] access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | -| LocalDataFlow.cs:261:15:261:20 | [post] access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:265:15:265:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:267:15:267:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:270:22:270:127 | (...) ... | LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | -| LocalDataFlow.cs:270:30:270:119 | call to method Insert | LocalDataFlow.cs:270:30:270:127 | call to method Clone | -| LocalDataFlow.cs:270:30:270:127 | call to method Clone | LocalDataFlow.cs:270:22:270:127 | (...) ... | -| LocalDataFlow.cs:271:15:271:20 | [post] access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:272:22:272:27 | [post] access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:63 | call to method Split | LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | -| LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:276:20:276:127 | (...) ... | LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:276:28:276:119 | call to method Insert | LocalDataFlow.cs:276:28:276:127 | call to method Clone | -| LocalDataFlow.cs:276:28:276:127 | call to method Clone | LocalDataFlow.cs:276:20:276:127 | (...) ... | -| LocalDataFlow.cs:277:15:277:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | LocalDataFlow.cs:279:15:279:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:278:25:278:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:68 | call to method Split | LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | -| LocalDataFlow.cs:283:15:283:20 | [post] access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:284:22:284:38 | call to method ToString | LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | -| LocalDataFlow.cs:285:15:285:20 | [post] access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | -| LocalDataFlow.cs:287:9:287:14 | [post] access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:292:15:292:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:293:20:293:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:39 | call to method ToString | LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:294:15:294:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:295:9:295:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | -| LocalDataFlow.cs:299:39:299:51 | [output] delegate creation of type Func | LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | -| LocalDataFlow.cs:299:39:299:51 | this access | LocalDataFlow.cs:309:42:309:57 | this access | -| LocalDataFlow.cs:300:15:300:20 | [post] access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:33 | access to property Value | -| LocalDataFlow.cs:301:22:301:33 | access to property Value | LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | -| LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | -| LocalDataFlow.cs:303:39:303:58 | [output] (...) => ... | LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | -| LocalDataFlow.cs:304:15:304:20 | [post] access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:33 | access to property Value | -| LocalDataFlow.cs:305:22:305:33 | access to property Value | LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | -| LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | -| LocalDataFlow.cs:309:42:309:57 | [output] delegate creation of type Func | LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | -| LocalDataFlow.cs:310:15:310:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | LocalDataFlow.cs:312:15:312:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:34 | access to property Value | -| LocalDataFlow.cs:311:20:311:34 | access to property Value | LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | -| LocalDataFlow.cs:313:38:313:45 | [output] (...) => ... | LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | -| LocalDataFlow.cs:314:15:314:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:34 | access to property Value | -| LocalDataFlow.cs:315:20:315:34 | access to property Value | LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:316:15:316:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:319:21:319:49 | object creation of type Dictionary | LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | -| LocalDataFlow.cs:320:9:320:13 | [post] access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | [post] access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:321:15:321:19 | [post] access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:322:22:322:26 | [post] access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:33 | access to property Values | LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | -| LocalDataFlow.cs:323:15:323:20 | [post] access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:324:22:324:37 | call to method Reverse | LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | -| LocalDataFlow.cs:328:9:328:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:22:329:26 | [post] access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:330:15:330:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | -| LocalDataFlow.cs:331:24:331:31 | [post] access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:38 | access to property Values | LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | -| LocalDataFlow.cs:332:15:332:22 | [post] access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | LocalDataFlow.cs:334:15:334:22 | access to local variable nonSink6 | -| LocalDataFlow.cs:333:24:333:41 | call to method Reverse | LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | -| LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:337:13:337:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:337:35:337:52 | object creation of type DataContract | LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:338:22:338:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:48 | access to property AString | LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | -| LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:340:22:340:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:46 | [post] access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:57 | access to property AString | LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | -| LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:344:38:344:55 | object creation of type DataContract | LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | LocalDataFlow.cs:346:15:346:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:345:20:345:49 | access to property AString | LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | LocalDataFlow.cs:348:15:348:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:347:20:347:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:44 | access to property AnInt | LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | LocalDataFlow.cs:350:15:350:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:349:20:349:53 | access to property AnInt | LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:353:34:353:37 | null | LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:354:22:354:40 | access to property Text | LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | -| LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:358:37:358:40 | null | LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | LocalDataFlow.cs:360:15:360:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:359:20:359:41 | access to property Text | LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | -| LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | -| LocalDataFlow.cs:366:15:366:20 | [post] access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:35 | access to property Current | -| LocalDataFlow.cs:367:22:367:35 | access to property Current | LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | -| LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:369:57:369:77 | (...) ... | LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | -| LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | LocalDataFlow.cs:369:57:369:77 | (...) ... | -| LocalDataFlow.cs:370:15:370:20 | [post] access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:35 | access to property Current | -| LocalDataFlow.cs:371:22:371:35 | access to property Current | LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | -| LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:33 | access to property Value | -| LocalDataFlow.cs:373:22:373:33 | access to property Value | LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | -| LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | LocalDataFlow.cs:378:19:378:27 | access to local variable nonSink17 | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | -| LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | -| LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | -| LocalDataFlow.cs:380:15:380:23 | [post] access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | LocalDataFlow.cs:382:15:382:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:36 | access to property Current | -| LocalDataFlow.cs:381:20:381:36 | access to property Current | LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | -| LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | -| LocalDataFlow.cs:383:63:383:86 | (...) ... | LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | -| LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | LocalDataFlow.cs:383:63:383:86 | (...) ... | -| LocalDataFlow.cs:384:15:384:23 | [post] access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | -| LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:41 | access to property Current | -| LocalDataFlow.cs:385:25:385:41 | access to property Current | LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | -| LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | -| LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | LocalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:34 | access to property Value | -| LocalDataFlow.cs:387:20:387:34 | access to property Value | LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:391:22:391:51 | call to method Run | LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | -| LocalDataFlow.cs:391:31:391:50 | [output] (...) => ... | LocalDataFlow.cs:391:22:391:51 | call to method Run | -| LocalDataFlow.cs:392:15:392:20 | [post] access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:393:22:393:33 | await ... | LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | -| LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | LocalDataFlow.cs:393:22:393:33 | await ... | -| LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:397:25:397:42 | call to method Run | LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:397:34:397:41 | [output] (...) => ... | LocalDataFlow.cs:397:25:397:42 | call to method Run | -| LocalDataFlow.cs:398:15:398:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:399:20:399:34 | await ... | LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | LocalDataFlow.cs:399:20:399:34 | await ... | -| LocalDataFlow.cs:400:15:400:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:403:22:403:36 | $"..." | LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | -| LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:407:20:407:37 | $"..." | LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:408:15:408:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | -| LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:415:20:415:38 | ... = ... | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | LocalDataFlow.cs:415:20:415:38 | ... = ... | -| LocalDataFlow.cs:416:15:416:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | -| LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | LocalDataFlow.cs:424:19:424:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | -| LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | -| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | -| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:483:21:483:21 | access to parameter x | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os | -| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... | -| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | +| 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 | | 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 | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index 6603abc50f1..eea36528104 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -65,17 +65,6 @@ public class LocalDataFlow nonSink0 += "abc"; Check(nonSink0); - // Assignment (indexer), tainted - var sink2 = new Dictionary(); - sink2[0][1] = sink1; - Check(sink2); - - // Assignment (indexer), not tainted - var nonSink1 = new Dictionary(); - nonSink1[""] = nonSink0; - nonSink1[sink1] = ""; // do not track tainted keys - Check(nonSink1); - // Concatenation, tainted var sink5 = sink1 + "ok"; Check(sink5); @@ -116,30 +105,6 @@ public class LocalDataFlow nonSink3 = nonSink0 as object; Check(nonSink3); - // Array creation (initializer), tainted - var sink10 = new object[] { sink9 }; - Check(sink10); - - // Array creation (initializer), not tainted - var nonSink4 = new object[] { 42 }; - Check(nonSink4); - - // Object creation (collection initializer), tainted - var sink11 = new Dictionary { { "", sink9 } }; - Check(sink11); - - // Object creation (collection initializer), not tainted - nonSink1 = new Dictionary { { sink9, "" } }; - Check(nonSink1); - - // Data-preserving LINQ, tainted - var sink14 = sink11.First(x => x.Value != null); - Check(sink14); - - // Data-preserving LINQ, not tainted - nonSink3 = nonSink1.First(x => x.Value != null); - Check(nonSink1); - // Standard method with a tainted argument, tainted var sink15 = Int32.Parse(sink9); Check(sink15); @@ -206,22 +171,6 @@ public class LocalDataFlow nonSink7 = sink8.Equals(nonSink3); Check(nonSink7); - // Indexer access, tainted - var sink23 = sink11[""]; - Check(sink23); - - // Indexer access, not tainted - nonSink0 = nonSink1[""]; - Check(nonSink0); - - // Array access, tainted - var sink24 = sink10[0]; - Check(sink24); - - // Array access, not tainted - nonSink3 = nonSink4[0]; - Check(nonSink3); - // Logical operation using tainted operand, tainted var sink25 = sink20 || false; Check(sink25); @@ -231,7 +180,7 @@ public class LocalDataFlow Check(nonSink7); // Ad hoc tracking (System.Uri), tainted - var sink26 = new System.Uri(sink23); + var sink26 = new System.Uri(sink9); Check(sink26); var sink27 = sink26.ToString(); Check(sink27); @@ -295,44 +244,6 @@ public class LocalDataFlow nonSink10.AppendLine(nonSink0); Check(nonSink10); - // Ad hoc tracking (System.Lazy), tainted - var sink40 = new Lazy(TaintedMethod); - Check(sink40); - var sink41 = sink40.Value; - Check(sink41); - var sink42 = new Lazy(() => "taint source"); - Check(sink42); - var sink43 = sink42.Value; - Check(sink43); - - // Ad hoc tracking (System.Lazy), not tainted - var nonSink12 = new Lazy(NonTaintedMethod); - Check(nonSink12); - nonSink0 = nonSink12.Value; - Check(nonSink0); - nonSink12 = new Lazy(() => ""); - Check(nonSink12); - nonSink0 = nonSink12.Value; - Check(nonSink0); - - // Ad hoc tracking (collections), tainted - var sink3 = new Dictionary(); - sink3.Add(0, sink1); - Check(sink3); - var sink12 = sink3.Values; - Check(sink12); - var sink13 = sink12.Reverse(); - Check(sink13); - - // Ad hoc tracking (collections), not tainted - nonSink1.Add("", nonSink0); - nonSink1.Add(sink1, ""); // do not track tainted keys - Check(nonSink1); - var nonSink5 = nonSink1.Values; - Check(nonSink5); - var nonSink6 = nonSink5.Reverse(); - Check(nonSink6); - // Ad hoc tracking (data contracts), tainted var taintedDataContract = new DataContract(); var sink53 = taintedDataContract.AString; @@ -359,34 +270,6 @@ public class LocalDataFlow nonSink0 = nonTaintedTextBox.Text; Check(nonSink0); - // Iteration over a tracked expression, tainted - foreach (var sink61 in sink10) - Check(sink61); - IEnumerator sink62 = sink10.GetEnumerator(); - Check(sink62); - var sink63 = sink62.Current; - Check(sink63); - IEnumerator> sink64 = sink3.GetEnumerator(); - Check(sink64); - var sink65 = sink64.Current; - Check(sink65); - var sink66 = sink65.Value; - Check(sink66); - - // Iteration over a tracked expression, not tainted - foreach (var nonSink17 in nonSink4) - Check(nonSink17); - IEnumerator nonSink18 = nonSink4.GetEnumerator(); - Check(nonSink18); - nonSink3 = nonSink18.Current; - Check(nonSink3); - IEnumerator> nonSink19 = nonSink1.GetEnumerator(); - Check(nonSink19); - var nonSink20 = nonSink19.Current; - Check(nonSink20); - nonSink0 = nonSink20.Value; - Check(nonSink0); - // async await, tainted var sink67 = Task.Run(() => "taint source"); Check(sink67); diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index 756d79333c1..e8a0153dc92 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,70 +1,51 @@ | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | +| 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 | | 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 8dd765a23cd..77195b49f3d 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -24,9 +24,7 @@ | 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:23:49:23 | this | LocalDataFlow.cs:299:39:299:51 | this access | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:49:30:49:30 | b | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | +| 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 | @@ -41,718 +39,610 @@ | 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:204:20:204:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:70:23:70:27 | 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: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:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:69:21:69:51 | object creation of type Dictionary | LocalDataFlow.cs:69:13:69:51 | SSA def(sink2) | -| LocalDataFlow.cs:70:9:70:13 | [post] access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:70:9:70:16 | access to indexer | -| LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:70:9:70:13 | access to local variable sink2 | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:70:9:70:16 | access to indexer | -| LocalDataFlow.cs:70:23:70:27 | access to local variable sink1 | LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | -| LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:74:24:74:55 | object creation of type Dictionary | LocalDataFlow.cs:74:13:74:55 | SSA def(nonSink1) | -| LocalDataFlow.cs:75:9:75:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:75:9:75:20 | access to indexer | -| LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | [post] access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:75:9:75:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:75:24:75:31 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:76:9:76:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:76:9:76:23 | access to indexer | -| LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | LocalDataFlow.cs:77:15:77:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:76:18:76:22 | [post] access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:18:76:22 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | -| LocalDataFlow.cs:76:27:76:28 | "" | LocalDataFlow.cs:76:9:76:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:80:21:80:32 | ... + ... | -| LocalDataFlow.cs:80:21:80:25 | access to local variable sink1 | LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | -| LocalDataFlow.cs:80:21:80:32 | ... + ... | LocalDataFlow.cs:80:13:80:32 | SSA def(sink5) | -| LocalDataFlow.cs:80:29:80:32 | "ok" | LocalDataFlow.cs:80:21:80:32 | ... + ... | -| LocalDataFlow.cs:81:15:81:19 | [post] access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | -| LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:84:20:84:27 | access to local variable nonSink0 | LocalDataFlow.cs:84:20:84:36 | ... + ... | -| LocalDataFlow.cs:84:20:84:36 | ... + ... | LocalDataFlow.cs:84:9:84:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:84:31:84:36 | "test" | LocalDataFlow.cs:84:20:84:36 | ... + ... | -| LocalDataFlow.cs:85:15:85:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | -| LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | [post] access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | -| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:101:15:101:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | -| LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | -| LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | LocalDataFlow.cs:104:21:104:33 | (...) ... | -| LocalDataFlow.cs:105:15:105:19 | [post] access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | -| LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | LocalDataFlow.cs:109:15:109:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:108:24:108:39 | (...) ... | LocalDataFlow.cs:108:13:108:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:108:24:108:39 | (...) ... | -| LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:112:21:112:35 | ... as ... | -| LocalDataFlow.cs:112:21:112:25 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | -| LocalDataFlow.cs:112:21:112:35 | ... as ... | LocalDataFlow.cs:112:13:112:35 | SSA def(sink9) | -| LocalDataFlow.cs:113:15:113:19 | [post] access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | -| LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | LocalDataFlow.cs:117:15:117:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:116:20:116:37 | ... as ... | -| LocalDataFlow.cs:116:20:116:27 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:20:116:37 | ... as ... | LocalDataFlow.cs:116:9:116:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | -| LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | LocalDataFlow.cs:120:13:120:43 | SSA def(sink10) | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:43 | array creation of type Object[] | -| LocalDataFlow.cs:120:37:120:41 | access to local variable sink9 | LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | -| LocalDataFlow.cs:121:15:121:20 | [post] access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | -| LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | -| LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | LocalDataFlow.cs:124:13:124:42 | SSA def(nonSink4) | -| LocalDataFlow.cs:124:39:124:40 | 42 | LocalDataFlow.cs:124:39:124:40 | (...) ... | -| LocalDataFlow.cs:124:39:124:40 | (...) ... | LocalDataFlow.cs:124:24:124:42 | array creation of type Object[] | -| LocalDataFlow.cs:125:15:125:22 | [post] access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:125:15:125:22 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | -| LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | -| LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | LocalDataFlow.cs:128:13:128:69 | SSA def(sink11) | -| LocalDataFlow.cs:128:61:128:65 | [post] access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:128:22:128:69 | object creation of type Dictionary | -| LocalDataFlow.cs:128:61:128:65 | access to local variable sink9 | LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | -| LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | LocalDataFlow.cs:132:9:132:67 | SSA def(nonSink1) | -| LocalDataFlow.cs:132:55:132:59 | [post] access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:55:132:59 | access to local variable sink9 | LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | -| LocalDataFlow.cs:132:62:132:63 | "" | LocalDataFlow.cs:132:20:132:67 | object creation of type Dictionary | -| LocalDataFlow.cs:133:15:133:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:133:15:133:22 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | -| LocalDataFlow.cs:136:22:136:27 | [post] access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:136:22:136:55 | call to method First | -| LocalDataFlow.cs:136:22:136:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | -| LocalDataFlow.cs:136:22:136:55 | call to method First | LocalDataFlow.cs:136:13:136:55 | SSA def(sink14) | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:35:136:35 | x | -| LocalDataFlow.cs:136:35:136:35 | x | LocalDataFlow.cs:136:40:136:40 | access to parameter x | -| LocalDataFlow.cs:136:40:136:40 | access to parameter x | LocalDataFlow.cs:136:40:136:46 | access to property Value | -| LocalDataFlow.cs:136:40:136:46 | access to property Value | LocalDataFlow.cs:136:40:136:54 | ... != ... | -| LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | LocalDataFlow.cs:206:33:206:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:140:20:140:55 | call to method First | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink1 | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:140:20:140:55 | (...) ... | LocalDataFlow.cs:140:9:140:55 | SSA def(nonSink3) | -| LocalDataFlow.cs:140:20:140:55 | call to method First | LocalDataFlow.cs:140:20:140:55 | (...) ... | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:35:140:35 | x | -| LocalDataFlow.cs:140:35:140:35 | x | LocalDataFlow.cs:140:40:140:40 | access to parameter x | -| LocalDataFlow.cs:140:40:140:40 | access to parameter x | LocalDataFlow.cs:140:40:140:46 | access to property Value | -| LocalDataFlow.cs:140:40:140:46 | access to property Value | LocalDataFlow.cs:140:40:140:54 | ... != ... | -| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | -| LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | -| LocalDataFlow.cs:144:22:144:39 | call to method Parse | LocalDataFlow.cs:144:13:144:39 | SSA def(sink15) | -| LocalDataFlow.cs:144:34:144:38 | [post] access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:144:22:144:39 | call to method Parse | -| LocalDataFlow.cs:144:34:144:38 | access to local variable sink9 | LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | -| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | -| LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | -| LocalDataFlow.cs:147:22:147:56 | call to method TryParse | LocalDataFlow.cs:147:13:147:56 | SSA def(sink16) | -| LocalDataFlow.cs:147:37:147:41 | [post] access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:147:22:147:56 | call to method TryParse | -| LocalDataFlow.cs:147:37:147:41 | access to local variable sink9 | LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | -| LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | -| LocalDataFlow.cs:149:22:149:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:149:22:149:49 | call to method Replace | -| LocalDataFlow.cs:149:22:149:29 | access to local variable nonSink0 | LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:149:22:149:49 | call to method Replace | LocalDataFlow.cs:149:13:149:49 | SSA def(sink17) | -| LocalDataFlow.cs:149:44:149:48 | [post] access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:149:22:149:49 | call to method Replace | -| LocalDataFlow.cs:149:44:149:48 | access to local variable sink9 | LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | -| LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | -| LocalDataFlow.cs:151:22:151:51 | call to method Format | LocalDataFlow.cs:151:13:151:51 | SSA def(sink18) | -| LocalDataFlow.cs:151:36:151:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:151:22:151:51 | call to method Format | -| LocalDataFlow.cs:151:36:151:43 | access to local variable nonSink0 | LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:46:151:50 | [post] access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:151:22:151:51 | call to method Format | -| LocalDataFlow.cs:151:46:151:50 | access to local variable sink9 | LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | -| LocalDataFlow.cs:152:15:152:20 | [post] access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | -| LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | -| LocalDataFlow.cs:153:22:153:52 | call to method Format | LocalDataFlow.cs:153:13:153:52 | SSA def(sink19) | -| LocalDataFlow.cs:153:36:153:41 | access to local variable sink18 | LocalDataFlow.cs:153:22:153:52 | call to method Format | -| LocalDataFlow.cs:153:44:153:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:153:22:153:52 | call to method Format | -| LocalDataFlow.cs:153:44:153:51 | access to local variable nonSink0 | LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | -| LocalDataFlow.cs:155:22:155:38 | call to method Parse | LocalDataFlow.cs:155:13:155:38 | SSA def(sink45) | -| LocalDataFlow.cs:155:33:155:37 | [post] access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:155:22:155:38 | call to method Parse | -| LocalDataFlow.cs:155:33:155:37 | access to local variable sink9 | LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | -| LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | -| LocalDataFlow.cs:158:22:158:56 | call to method TryParse | LocalDataFlow.cs:158:13:158:56 | SSA def(sink46) | -| LocalDataFlow.cs:158:36:158:40 | [post] access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:158:22:158:56 | call to method TryParse | -| LocalDataFlow.cs:158:36:158:40 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | -| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | -| LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | -| LocalDataFlow.cs:160:22:160:43 | call to method ToByte | LocalDataFlow.cs:160:13:160:43 | SSA def(sink47) | -| LocalDataFlow.cs:160:37:160:42 | access to local variable sink46 | LocalDataFlow.cs:160:22:160:43 | call to method ToByte | -| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | -| LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | -| LocalDataFlow.cs:162:22:162:46 | call to method Concat | LocalDataFlow.cs:162:13:162:46 | SSA def(sink49) | -| LocalDataFlow.cs:162:36:162:37 | "" | LocalDataFlow.cs:162:22:162:46 | call to method Concat | -| LocalDataFlow.cs:162:40:162:45 | (...) ... | LocalDataFlow.cs:162:22:162:46 | call to method Concat | -| LocalDataFlow.cs:162:40:162:45 | access to local variable sink47 | LocalDataFlow.cs:162:40:162:45 | (...) ... | -| LocalDataFlow.cs:163:15:163:20 | [post] access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | -| LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | -| LocalDataFlow.cs:164:22:164:40 | call to method Copy | LocalDataFlow.cs:164:13:164:40 | SSA def(sink50) | -| LocalDataFlow.cs:164:34:164:39 | access to local variable sink49 | LocalDataFlow.cs:164:22:164:40 | call to method Copy | -| LocalDataFlow.cs:165:15:165:20 | [post] access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | -| LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | -| LocalDataFlow.cs:166:22:166:54 | call to method Join | LocalDataFlow.cs:166:13:166:54 | SSA def(sink51) | -| LocalDataFlow.cs:166:34:166:37 | ", " | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:40:166:41 | "" | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:44:166:49 | access to local variable sink50 | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:166:52:166:53 | "" | LocalDataFlow.cs:166:22:166:54 | call to method Join | -| LocalDataFlow.cs:167:15:167:20 | [post] access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | -| LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | -| LocalDataFlow.cs:168:22:168:23 | "" | LocalDataFlow.cs:168:22:168:41 | call to method Insert | -| LocalDataFlow.cs:168:22:168:41 | call to method Insert | LocalDataFlow.cs:168:13:168:41 | SSA def(sink52) | -| LocalDataFlow.cs:168:35:168:40 | access to local variable sink51 | LocalDataFlow.cs:168:22:168:41 | call to method Insert | -| LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | LocalDataFlow.cs:173:15:173:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:172:20:172:40 | call to method Parse | LocalDataFlow.cs:172:9:172:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:172:32:172:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:172:20:172:40 | call to method Parse | -| LocalDataFlow.cs:172:32:172:39 | access to local variable nonSink0 | LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | LocalDataFlow.cs:175:15:175:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:174:24:174:61 | call to method TryParse | LocalDataFlow.cs:174:13:174:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:174:39:174:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:174:24:174:61 | call to method TryParse | -| LocalDataFlow.cs:174:39:174:46 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:50 | call to method Replace | -| LocalDataFlow.cs:176:20:176:27 | access to local variable nonSink0 | LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:176:20:176:50 | call to method Replace | LocalDataFlow.cs:176:9:176:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:176:42:176:49 | access to local variable nonSink0 | LocalDataFlow.cs:176:20:176:50 | call to method Replace | -| LocalDataFlow.cs:177:15:177:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:177:15:177:22 | access to local variable nonSink0 | LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:20:178:52 | call to method Format | LocalDataFlow.cs:178:9:178:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:178:34:178:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:20:178:52 | call to method Format | -| LocalDataFlow.cs:178:34:178:41 | access to local variable nonSink0 | LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:178:44:178:51 | access to local variable nonSink0 | LocalDataFlow.cs:178:20:178:52 | call to method Format | -| LocalDataFlow.cs:179:15:179:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink0 | LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | LocalDataFlow.cs:181:15:181:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:180:20:180:39 | call to method Parse | LocalDataFlow.cs:180:9:180:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:180:31:180:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:180:20:180:39 | call to method Parse | -| LocalDataFlow.cs:180:31:180:38 | access to local variable nonSink0 | LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:182:20:182:57 | call to method TryParse | LocalDataFlow.cs:182:9:182:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:182:34:182:41 | access to local variable nonSink0 | LocalDataFlow.cs:182:20:182:57 | call to method TryParse | -| LocalDataFlow.cs:183:15:183:22 | access to local variable nonSink7 | LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | LocalDataFlow.cs:185:15:185:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:184:25:184:48 | call to method ToByte | LocalDataFlow.cs:184:13:184:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:184:25:184:48 | call to method ToByte | -| LocalDataFlow.cs:184:40:184:47 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:186:20:186:46 | call to method Concat | LocalDataFlow.cs:186:9:186:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:186:34:186:35 | "" | LocalDataFlow.cs:186:20:186:46 | call to method Concat | -| LocalDataFlow.cs:186:38:186:45 | (...) ... | LocalDataFlow.cs:186:20:186:46 | call to method Concat | -| LocalDataFlow.cs:186:38:186:45 | access to local variable nonSink7 | LocalDataFlow.cs:186:38:186:45 | (...) ... | -| LocalDataFlow.cs:187:15:187:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:187:15:187:22 | access to local variable nonSink0 | LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:188:20:188:40 | call to method Copy | LocalDataFlow.cs:188:9:188:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:188:32:188:39 | access to local variable nonSink0 | LocalDataFlow.cs:188:20:188:40 | call to method Copy | -| LocalDataFlow.cs:189:15:189:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:189:15:189:22 | access to local variable nonSink0 | LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:190:20:190:54 | call to method Join | LocalDataFlow.cs:190:9:190:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:190:32:190:35 | ", " | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:38:190:39 | "" | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:42:190:49 | access to local variable nonSink0 | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:190:52:190:53 | "" | LocalDataFlow.cs:190:20:190:54 | call to method Join | -| LocalDataFlow.cs:191:15:191:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:191:15:191:22 | access to local variable nonSink0 | LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | LocalDataFlow.cs:193:15:193:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:192:20:192:21 | "" | LocalDataFlow.cs:192:20:192:41 | call to method Insert | -| LocalDataFlow.cs:192:20:192:41 | call to method Insert | LocalDataFlow.cs:192:9:192:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:192:33:192:40 | access to local variable nonSink0 | LocalDataFlow.cs:192:20:192:41 | call to method Insert | -| LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | -| LocalDataFlow.cs:196:22:196:27 | access to local variable sink15 | LocalDataFlow.cs:196:22:196:32 | ... > ... | -| LocalDataFlow.cs:196:22:196:32 | ... > ... | LocalDataFlow.cs:196:13:196:32 | SSA def(sink20) | -| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | -| LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | -| LocalDataFlow.cs:198:22:198:26 | access to local variable sink9 | LocalDataFlow.cs:198:22:198:40 | call to method Equals | -| LocalDataFlow.cs:198:22:198:40 | call to method Equals | LocalDataFlow.cs:198:13:198:40 | SSA def(sink21) | -| LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | -| LocalDataFlow.cs:200:22:200:26 | [post] access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:200:22:200:45 | call to method Equals | -| LocalDataFlow.cs:200:22:200:26 | access to local variable sink8 | LocalDataFlow.cs:206:20:206:24 | access to local variable sink8 | -| LocalDataFlow.cs:200:22:200:45 | call to method Equals | LocalDataFlow.cs:200:13:200:45 | SSA def(sink22) | -| LocalDataFlow.cs:200:43:200:44 | 41 | LocalDataFlow.cs:200:35:200:44 | (...) ... | -| LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | LocalDataFlow.cs:205:15:205:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:204:20:204:24 | [post] access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:24 | access to local variable sink0 | LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | -| LocalDataFlow.cs:204:20:204:38 | call to method Equals | LocalDataFlow.cs:204:9:204:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:204:33:204:37 | [post] access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:204:33:204:37 | access to local variable sink1 | LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | -| LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:206:20:206:41 | call to method Equals | LocalDataFlow.cs:206:9:206:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:207:15:207:22 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | -| LocalDataFlow.cs:210:22:210:27 | access to local variable sink11 | LocalDataFlow.cs:210:22:210:31 | access to indexer | -| LocalDataFlow.cs:210:22:210:31 | access to indexer | LocalDataFlow.cs:210:13:210:31 | SSA def(sink23) | -| LocalDataFlow.cs:211:15:211:20 | [post] access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | -| LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:214:20:214:27 | [post] access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:214:20:214:31 | access to indexer | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink1 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:214:20:214:31 | access to indexer | LocalDataFlow.cs:214:9:214:31 | SSA def(nonSink0) | -| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:218:22:218:30 | access to array element | -| LocalDataFlow.cs:218:22:218:27 | access to local variable sink10 | LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | -| LocalDataFlow.cs:218:22:218:30 | access to array element | LocalDataFlow.cs:218:13:218:30 | SSA def(sink24) | -| LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | LocalDataFlow.cs:223:15:223:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:222:20:222:30 | access to array element | -| LocalDataFlow.cs:222:20:222:27 | access to local variable nonSink4 | LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | -| LocalDataFlow.cs:222:20:222:30 | access to array element | LocalDataFlow.cs:222:9:222:30 | SSA def(nonSink3) | -| LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | -| LocalDataFlow.cs:226:22:226:27 | access to local variable sink20 | LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | -| LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | LocalDataFlow.cs:226:13:226:36 | SSA def(sink25) | -| LocalDataFlow.cs:226:32:226:36 | false | LocalDataFlow.cs:226:22:226:36 | ... \|\| ... | -| LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | LocalDataFlow.cs:231:15:231:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:230:20:230:27 | access to local variable nonSink7 | LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | -| LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | LocalDataFlow.cs:230:9:230:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:230:32:230:36 | false | LocalDataFlow.cs:230:20:230:36 | ... \|\| ... | -| LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | -| LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | LocalDataFlow.cs:234:13:234:43 | SSA def(sink26) | -| LocalDataFlow.cs:234:37:234:42 | access to local variable sink23 | LocalDataFlow.cs:234:22:234:43 | object creation of type Uri | -| LocalDataFlow.cs:235:15:235:20 | [post] access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | -| LocalDataFlow.cs:236:22:236:27 | [post] access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:236:22:236:38 | call to method ToString | -| LocalDataFlow.cs:236:22:236:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | -| LocalDataFlow.cs:236:22:236:38 | call to method ToString | LocalDataFlow.cs:236:13:236:38 | SSA def(sink27) | -| LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | -| LocalDataFlow.cs:238:22:238:27 | [post] access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | -| LocalDataFlow.cs:238:22:238:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | -| LocalDataFlow.cs:238:22:238:40 | access to property PathAndQuery | LocalDataFlow.cs:238:13:238:40 | SSA def(sink28) | -| LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | -| LocalDataFlow.cs:240:22:240:27 | [post] access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:240:22:240:33 | access to property Query | -| LocalDataFlow.cs:240:22:240:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | -| LocalDataFlow.cs:240:22:240:33 | access to property Query | LocalDataFlow.cs:240:13:240:33 | SSA def(sink29) | -| LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | -| LocalDataFlow.cs:242:22:242:27 | access to local variable sink26 | LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | -| LocalDataFlow.cs:242:22:242:42 | access to property OriginalString | LocalDataFlow.cs:242:13:242:42 | SSA def(sink30) | -| LocalDataFlow.cs:243:15:243:20 | [post] access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | -| LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | LocalDataFlow.cs:246:13:246:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:246:39:246:46 | access to local variable nonSink0 | LocalDataFlow.cs:246:24:246:47 | object creation of type Uri | -| LocalDataFlow.cs:247:15:247:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:247:15:247:22 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | LocalDataFlow.cs:249:15:249:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:248:20:248:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:248:20:248:38 | call to method ToString | -| LocalDataFlow.cs:248:20:248:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:248:20:248:38 | call to method ToString | LocalDataFlow.cs:248:9:248:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | LocalDataFlow.cs:251:15:251:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:250:20:250:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | -| LocalDataFlow.cs:250:20:250:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:250:20:250:40 | access to property PathAndQuery | LocalDataFlow.cs:250:9:250:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | LocalDataFlow.cs:253:15:253:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:252:20:252:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:252:20:252:33 | access to property Query | -| LocalDataFlow.cs:252:20:252:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:252:20:252:33 | access to property Query | LocalDataFlow.cs:252:9:252:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:254:20:254:27 | access to local variable nonSink8 | LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | -| LocalDataFlow.cs:254:20:254:42 | access to property OriginalString | LocalDataFlow.cs:254:9:254:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:255:15:255:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:255:15:255:22 | access to local variable nonSink0 | LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | -| LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | LocalDataFlow.cs:258:13:258:55 | SSA def(sink31) | -| LocalDataFlow.cs:258:49:258:54 | access to local variable sink30 | LocalDataFlow.cs:258:22:258:55 | object creation of type StringReader | -| LocalDataFlow.cs:259:15:259:20 | [post] access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | -| LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | -| LocalDataFlow.cs:260:22:260:27 | access to local variable sink31 | LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | -| LocalDataFlow.cs:260:22:260:39 | call to method ReadToEnd | LocalDataFlow.cs:260:13:260:39 | SSA def(sink32) | -| LocalDataFlow.cs:261:15:261:20 | [post] access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | -| LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | LocalDataFlow.cs:264:13:264:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:264:51:264:58 | access to local variable nonSink0 | LocalDataFlow.cs:264:24:264:59 | object creation of type StringReader | -| LocalDataFlow.cs:265:15:265:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:265:15:265:22 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:266:20:266:27 | access to local variable nonSink9 | LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | -| LocalDataFlow.cs:266:20:266:39 | call to method ReadToEnd | LocalDataFlow.cs:266:9:266:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:267:15:267:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:267:15:267:22 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | -| LocalDataFlow.cs:270:22:270:127 | (...) ... | LocalDataFlow.cs:270:13:270:127 | SSA def(sink33) | -| LocalDataFlow.cs:270:30:270:35 | access to local variable sink32 | LocalDataFlow.cs:270:30:270:48 | call to method Substring | -| LocalDataFlow.cs:270:30:270:48 | call to method Substring | LocalDataFlow.cs:270:30:270:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:270:30:270:67 | call to method ToLowerInvariant | LocalDataFlow.cs:270:30:270:77 | call to method ToUpper | -| LocalDataFlow.cs:270:30:270:77 | call to method ToUpper | LocalDataFlow.cs:270:30:270:87 | call to method Trim | -| LocalDataFlow.cs:270:30:270:87 | call to method Trim | LocalDataFlow.cs:270:30:270:105 | call to method Replace | -| LocalDataFlow.cs:270:30:270:105 | call to method Replace | LocalDataFlow.cs:270:30:270:119 | call to method Insert | -| LocalDataFlow.cs:270:30:270:119 | call to method Insert | LocalDataFlow.cs:270:30:270:127 | call to method Clone | -| LocalDataFlow.cs:270:30:270:127 | call to method Clone | LocalDataFlow.cs:270:22:270:127 | (...) ... | -| LocalDataFlow.cs:270:102:270:104 | "b" | LocalDataFlow.cs:270:30:270:105 | call to method Replace | -| LocalDataFlow.cs:270:117:270:118 | "" | LocalDataFlow.cs:270:30:270:119 | call to method Insert | -| LocalDataFlow.cs:271:15:271:20 | [post] access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | -| LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | -| LocalDataFlow.cs:272:22:272:27 | [post] access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:272:22:272:39 | call to method Normalize | -| LocalDataFlow.cs:272:22:272:27 | access to local variable sink33 | LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | -| LocalDataFlow.cs:272:22:272:39 | call to method Normalize | LocalDataFlow.cs:272:22:272:52 | call to method Remove | -| LocalDataFlow.cs:272:22:272:52 | call to method Remove | LocalDataFlow.cs:272:22:272:63 | call to method Split | -| LocalDataFlow.cs:272:22:272:63 | call to method Split | LocalDataFlow.cs:272:13:272:63 | SSA def(sink48) | -| LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:276:20:276:127 | (...) ... | LocalDataFlow.cs:276:9:276:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:276:28:276:35 | access to local variable nonSink0 | LocalDataFlow.cs:276:28:276:48 | call to method Substring | -| LocalDataFlow.cs:276:28:276:48 | call to method Substring | LocalDataFlow.cs:276:28:276:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:276:28:276:67 | call to method ToLowerInvariant | LocalDataFlow.cs:276:28:276:77 | call to method ToUpper | -| LocalDataFlow.cs:276:28:276:77 | call to method ToUpper | LocalDataFlow.cs:276:28:276:87 | call to method Trim | -| LocalDataFlow.cs:276:28:276:87 | call to method Trim | LocalDataFlow.cs:276:28:276:105 | call to method Replace | -| LocalDataFlow.cs:276:28:276:105 | call to method Replace | LocalDataFlow.cs:276:28:276:119 | call to method Insert | -| LocalDataFlow.cs:276:28:276:119 | call to method Insert | LocalDataFlow.cs:276:28:276:127 | call to method Clone | -| LocalDataFlow.cs:276:28:276:127 | call to method Clone | LocalDataFlow.cs:276:20:276:127 | (...) ... | -| LocalDataFlow.cs:276:102:276:104 | "b" | LocalDataFlow.cs:276:28:276:105 | call to method Replace | -| LocalDataFlow.cs:276:117:276:118 | "" | LocalDataFlow.cs:276:28:276:119 | call to method Insert | -| LocalDataFlow.cs:277:15:277:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:277:15:277:22 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | LocalDataFlow.cs:279:15:279:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:278:25:278:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:278:25:278:44 | call to method Normalize | -| LocalDataFlow.cs:278:25:278:32 | access to local variable nonSink0 | LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:278:25:278:44 | call to method Normalize | LocalDataFlow.cs:278:25:278:57 | call to method Remove | -| LocalDataFlow.cs:278:25:278:57 | call to method Remove | LocalDataFlow.cs:278:25:278:68 | call to method Split | -| LocalDataFlow.cs:278:25:278:68 | call to method Split | LocalDataFlow.cs:278:13:278:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | -| LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | LocalDataFlow.cs:282:13:282:46 | SSA def(sink34) | -| LocalDataFlow.cs:282:40:282:45 | access to local variable sink33 | LocalDataFlow.cs:282:22:282:46 | object creation of type StringBuilder | -| LocalDataFlow.cs:283:15:283:20 | [post] access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | -| LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | -| LocalDataFlow.cs:284:22:284:27 | access to local variable sink34 | LocalDataFlow.cs:284:22:284:38 | call to method ToString | -| LocalDataFlow.cs:284:22:284:38 | call to method ToString | LocalDataFlow.cs:284:13:284:38 | SSA def(sink35) | -| LocalDataFlow.cs:285:15:285:20 | [post] access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | -| LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | LocalDataFlow.cs:286:13:286:42 | SSA def(sink36) | -| LocalDataFlow.cs:286:40:286:41 | "" | LocalDataFlow.cs:286:22:286:42 | object creation of type StringBuilder | -| LocalDataFlow.cs:287:9:287:14 | [post] access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | -| LocalDataFlow.cs:287:27:287:32 | access to local variable sink35 | LocalDataFlow.cs:287:9:287:14 | access to local variable sink36 | -| LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | LocalDataFlow.cs:291:13:291:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:291:43:291:50 | access to local variable nonSink0 | LocalDataFlow.cs:291:25:291:51 | object creation of type StringBuilder | -| LocalDataFlow.cs:292:15:292:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:292:15:292:23 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:293:20:293:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:293:20:293:39 | call to method ToString | -| LocalDataFlow.cs:293:20:293:28 | access to local variable nonSink10 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:293:20:293:39 | call to method ToString | LocalDataFlow.cs:293:9:293:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:294:15:294:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:15:294:22 | access to local variable nonSink0 | LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:295:9:295:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | LocalDataFlow.cs:296:15:296:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:295:30:295:37 | access to local variable nonSink0 | LocalDataFlow.cs:295:9:295:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | -| LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | LocalDataFlow.cs:299:13:299:52 | SSA def(sink40) | -| LocalDataFlow.cs:299:39:299:51 | [output] delegate creation of type Func | LocalDataFlow.cs:299:22:299:52 | object creation of type Lazy | -| LocalDataFlow.cs:299:39:299:51 | this access | LocalDataFlow.cs:309:42:309:57 | this access | -| LocalDataFlow.cs:300:15:300:20 | [post] access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | -| LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | -| LocalDataFlow.cs:301:22:301:27 | access to local variable sink40 | LocalDataFlow.cs:301:22:301:33 | access to property Value | -| LocalDataFlow.cs:301:22:301:33 | access to property Value | LocalDataFlow.cs:301:13:301:33 | SSA def(sink41) | -| LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | -| LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | LocalDataFlow.cs:303:13:303:59 | SSA def(sink42) | -| LocalDataFlow.cs:303:39:303:58 | [output] (...) => ... | LocalDataFlow.cs:303:22:303:59 | object creation of type Lazy | -| LocalDataFlow.cs:304:15:304:20 | [post] access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | -| LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | -| LocalDataFlow.cs:305:22:305:27 | access to local variable sink42 | LocalDataFlow.cs:305:22:305:33 | access to property Value | -| LocalDataFlow.cs:305:22:305:33 | access to property Value | LocalDataFlow.cs:305:13:305:33 | SSA def(sink43) | -| LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | LocalDataFlow.cs:309:13:309:58 | SSA def(nonSink12) | -| LocalDataFlow.cs:309:42:309:57 | [output] delegate creation of type Func | LocalDataFlow.cs:309:25:309:58 | object creation of type Lazy | -| LocalDataFlow.cs:310:15:310:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:310:15:310:23 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | LocalDataFlow.cs:312:15:312:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:311:20:311:28 | access to local variable nonSink12 | LocalDataFlow.cs:311:20:311:34 | access to property Value | -| LocalDataFlow.cs:311:20:311:34 | access to property Value | LocalDataFlow.cs:311:9:311:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | -| LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | LocalDataFlow.cs:313:9:313:46 | SSA def(nonSink12) | -| LocalDataFlow.cs:313:38:313:45 | [output] (...) => ... | LocalDataFlow.cs:313:21:313:46 | object creation of type Lazy | -| LocalDataFlow.cs:314:15:314:23 | [post] access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:314:15:314:23 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | -| LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:315:20:315:28 | access to local variable nonSink12 | LocalDataFlow.cs:315:20:315:34 | access to property Value | -| LocalDataFlow.cs:315:20:315:34 | access to property Value | LocalDataFlow.cs:315:9:315:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:316:15:316:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:316:15:316:22 | access to local variable nonSink0 | LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | -| LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:319:21:319:49 | object creation of type Dictionary | LocalDataFlow.cs:319:13:319:49 | SSA def(sink3) | -| LocalDataFlow.cs:320:9:320:13 | [post] access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | [post] access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:320:9:320:13 | access to local variable sink3 | -| LocalDataFlow.cs:320:22:320:26 | access to local variable sink1 | LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | -| LocalDataFlow.cs:321:15:321:19 | [post] access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | -| LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | -| LocalDataFlow.cs:322:22:322:26 | [post] access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:322:22:322:33 | access to property Values | -| LocalDataFlow.cs:322:22:322:26 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | -| LocalDataFlow.cs:322:22:322:33 | access to property Values | LocalDataFlow.cs:322:13:322:33 | SSA def(sink12) | -| LocalDataFlow.cs:323:15:323:20 | [post] access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | -| LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | -| LocalDataFlow.cs:324:22:324:27 | access to local variable sink12 | LocalDataFlow.cs:324:22:324:37 | call to method Reverse | -| LocalDataFlow.cs:324:22:324:37 | call to method Reverse | LocalDataFlow.cs:324:13:324:37 | SSA def(sink13) | -| LocalDataFlow.cs:328:9:328:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:328:26:328:33 | access to local variable nonSink0 | LocalDataFlow.cs:328:9:328:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | [post] access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | -| LocalDataFlow.cs:329:22:329:26 | [post] access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:22:329:26 | access to local variable sink1 | LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | -| LocalDataFlow.cs:329:29:329:30 | "" | LocalDataFlow.cs:329:9:329:16 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | [post] access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:330:15:330:22 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | -| LocalDataFlow.cs:331:24:331:31 | [post] access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:331:24:331:38 | access to property Values | -| LocalDataFlow.cs:331:24:331:31 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | -| LocalDataFlow.cs:331:24:331:38 | access to property Values | LocalDataFlow.cs:331:13:331:38 | SSA def(nonSink5) | -| LocalDataFlow.cs:332:15:332:22 | [post] access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:332:15:332:22 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | -| LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | LocalDataFlow.cs:334:15:334:22 | access to local variable nonSink6 | -| LocalDataFlow.cs:333:24:333:31 | access to local variable nonSink5 | LocalDataFlow.cs:333:24:333:41 | call to method Reverse | -| LocalDataFlow.cs:333:24:333:41 | call to method Reverse | LocalDataFlow.cs:333:13:333:41 | SSA def(nonSink6) | -| LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:337:13:337:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:337:35:337:52 | object creation of type DataContract | LocalDataFlow.cs:337:13:337:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | -| LocalDataFlow.cs:338:22:338:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:338:22:338:48 | access to property AString | -| LocalDataFlow.cs:338:22:338:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:338:22:338:48 | access to property AString | LocalDataFlow.cs:338:13:338:48 | SSA def(sink53) | -| LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | -| LocalDataFlow.cs:340:22:340:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:340:22:340:46 | access to property AList | -| LocalDataFlow.cs:340:22:340:40 | access to local variable taintedDataContract | LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:340:22:340:46 | [post] access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:340:22:340:49 | access to indexer | -| LocalDataFlow.cs:340:22:340:46 | access to property AList | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:340:22:340:49 | access to indexer | LocalDataFlow.cs:340:22:340:57 | access to property AString | -| LocalDataFlow.cs:340:22:340:57 | access to property AString | LocalDataFlow.cs:340:13:340:57 | SSA def(sink54) | -| LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:344:38:344:55 | object creation of type DataContract | LocalDataFlow.cs:344:13:344:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | LocalDataFlow.cs:346:15:346:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:345:20:345:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:345:20:345:49 | access to property AString | -| LocalDataFlow.cs:345:20:345:49 | access to property AString | LocalDataFlow.cs:345:9:345:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | LocalDataFlow.cs:348:15:348:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:347:20:347:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:347:20:347:44 | access to property AnInt | LocalDataFlow.cs:347:9:347:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | LocalDataFlow.cs:350:15:350:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:349:20:349:38 | access to local variable taintedDataContract | LocalDataFlow.cs:349:20:349:44 | access to property AList | -| LocalDataFlow.cs:349:20:349:44 | access to property AList | LocalDataFlow.cs:349:20:349:47 | access to indexer | -| LocalDataFlow.cs:349:20:349:53 | access to property AnInt | LocalDataFlow.cs:349:9:349:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:353:34:353:37 | null | LocalDataFlow.cs:353:17:353:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | -| LocalDataFlow.cs:354:22:354:35 | access to local variable taintedTextBox | LocalDataFlow.cs:354:22:354:40 | access to property Text | -| LocalDataFlow.cs:354:22:354:40 | access to property Text | LocalDataFlow.cs:354:13:354:40 | SSA def(sink60) | -| LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:358:37:358:40 | null | LocalDataFlow.cs:358:17:358:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | LocalDataFlow.cs:360:15:360:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:359:20:359:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:359:20:359:41 | access to property Text | -| LocalDataFlow.cs:359:20:359:41 | access to property Text | LocalDataFlow.cs:359:9:359:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:363:22:363:27 | SSA def(sink61) | -| LocalDataFlow.cs:363:32:363:37 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | -| LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | -| LocalDataFlow.cs:365:30:365:35 | access to local variable sink10 | LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | -| LocalDataFlow.cs:365:30:365:51 | call to method GetEnumerator | LocalDataFlow.cs:365:21:365:51 | SSA def(sink62) | -| LocalDataFlow.cs:366:15:366:20 | [post] access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | -| LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | -| LocalDataFlow.cs:367:22:367:27 | access to local variable sink62 | LocalDataFlow.cs:367:22:367:35 | access to property Current | -| LocalDataFlow.cs:367:22:367:35 | access to property Current | LocalDataFlow.cs:367:13:367:35 | SSA def(sink63) | -| LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | -| LocalDataFlow.cs:369:57:369:61 | access to local variable sink3 | LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | -| LocalDataFlow.cs:369:57:369:77 | (...) ... | LocalDataFlow.cs:369:48:369:77 | SSA def(sink64) | -| LocalDataFlow.cs:369:57:369:77 | call to method GetEnumerator | LocalDataFlow.cs:369:57:369:77 | (...) ... | -| LocalDataFlow.cs:370:15:370:20 | [post] access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | -| LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | -| LocalDataFlow.cs:371:22:371:27 | access to local variable sink64 | LocalDataFlow.cs:371:22:371:35 | access to property Current | -| LocalDataFlow.cs:371:22:371:35 | access to property Current | LocalDataFlow.cs:371:13:371:35 | SSA def(sink65) | -| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | -| LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | -| LocalDataFlow.cs:373:22:373:27 | access to local variable sink65 | LocalDataFlow.cs:373:22:373:33 | access to property Value | -| LocalDataFlow.cs:373:22:373:33 | access to property Value | LocalDataFlow.cs:373:13:373:33 | SSA def(sink66) | -| LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | LocalDataFlow.cs:378:19:378:27 | access to local variable nonSink17 | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:377:22:377:30 | SSA def(nonSink17) | -| LocalDataFlow.cs:377:35:377:42 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | -| LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | -| LocalDataFlow.cs:379:33:379:40 | access to local variable nonSink4 | LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | -| LocalDataFlow.cs:379:33:379:56 | call to method GetEnumerator | LocalDataFlow.cs:379:21:379:56 | SSA def(nonSink18) | -| LocalDataFlow.cs:380:15:380:23 | [post] access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:380:15:380:23 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | -| LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | LocalDataFlow.cs:382:15:382:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:381:20:381:28 | access to local variable nonSink18 | LocalDataFlow.cs:381:20:381:36 | access to property Current | -| LocalDataFlow.cs:381:20:381:36 | access to property Current | LocalDataFlow.cs:381:9:381:36 | SSA def(nonSink3) | -| LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | -| LocalDataFlow.cs:383:63:383:70 | access to local variable nonSink1 | LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | -| LocalDataFlow.cs:383:63:383:86 | (...) ... | LocalDataFlow.cs:383:51:383:86 | SSA def(nonSink19) | -| LocalDataFlow.cs:383:63:383:86 | call to method GetEnumerator | LocalDataFlow.cs:383:63:383:86 | (...) ... | -| LocalDataFlow.cs:384:15:384:23 | [post] access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:384:15:384:23 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | -| LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | -| LocalDataFlow.cs:385:25:385:33 | access to local variable nonSink19 | LocalDataFlow.cs:385:25:385:41 | access to property Current | -| LocalDataFlow.cs:385:25:385:41 | access to property Current | LocalDataFlow.cs:385:13:385:41 | SSA def(nonSink20) | -| LocalDataFlow.cs:386:15:386:23 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | -| LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | LocalDataFlow.cs:388:15:388:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:387:20:387:28 | access to local variable nonSink20 | LocalDataFlow.cs:387:20:387:34 | access to property Value | -| LocalDataFlow.cs:387:20:387:34 | access to property Value | LocalDataFlow.cs:387:9:387:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | -| LocalDataFlow.cs:391:22:391:51 | call to method Run | LocalDataFlow.cs:391:13:391:51 | SSA def(sink67) | -| LocalDataFlow.cs:391:31:391:50 | [output] (...) => ... | LocalDataFlow.cs:391:22:391:51 | call to method Run | -| LocalDataFlow.cs:392:15:392:20 | [post] access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | -| LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | -| LocalDataFlow.cs:393:22:393:33 | await ... | LocalDataFlow.cs:393:13:393:33 | SSA def(sink68) | -| LocalDataFlow.cs:393:28:393:33 | access to local variable sink67 | LocalDataFlow.cs:393:22:393:33 | await ... | -| LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:397:25:397:42 | call to method Run | LocalDataFlow.cs:397:13:397:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:397:34:397:41 | [output] (...) => ... | LocalDataFlow.cs:397:25:397:42 | call to method Run | -| LocalDataFlow.cs:398:15:398:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:398:15:398:23 | access to local variable nonSink21 | LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:399:20:399:34 | await ... | LocalDataFlow.cs:399:9:399:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:399:26:399:34 | access to local variable nonSink21 | LocalDataFlow.cs:399:20:399:34 | await ... | -| LocalDataFlow.cs:400:15:400:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:400:15:400:22 | access to local variable nonSink0 | LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | -| LocalDataFlow.cs:403:22:403:36 | $"..." | LocalDataFlow.cs:403:13:403:36 | SSA def(sink69) | -| LocalDataFlow.cs:403:24:403:28 | "test " | LocalDataFlow.cs:403:22:403:36 | $"..." | -| LocalDataFlow.cs:403:30:403:34 | access to local variable sink1 | LocalDataFlow.cs:403:22:403:36 | $"..." | -| LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:407:20:407:37 | $"..." | LocalDataFlow.cs:407:9:407:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:407:22:407:26 | "test " | LocalDataFlow.cs:407:20:407:37 | $"..." | -| LocalDataFlow.cs:407:28:407:35 | access to local variable nonSink0 | LocalDataFlow.cs:407:20:407:37 | $"..." | -| LocalDataFlow.cs:408:15:408:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:408:15:408:22 | access to local variable nonSink0 | LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | -| LocalDataFlow.cs:411:22:411:34 | ... = ... | LocalDataFlow.cs:411:13:411:34 | SSA def(sink70) | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | -| LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | ... = ... | -| LocalDataFlow.cs:411:30:411:34 | access to local variable sink0 | LocalDataFlow.cs:411:22:411:34 | SSA def(sink0) | -| LocalDataFlow.cs:412:15:412:20 | [post] access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | -| LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:415:20:415:38 | ... = ... | LocalDataFlow.cs:415:9:415:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:415:31:415:38 | access to local variable nonSink0 | LocalDataFlow.cs:415:20:415:38 | ... = ... | -| LocalDataFlow.cs:416:15:416:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:416:15:416:22 | access to local variable nonSink0 | LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | -| LocalDataFlow.cs:419:13:419:18 | access to local variable sink70 | LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | -| LocalDataFlow.cs:419:23:419:35 | SSA def(sink71) | LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:423:13:423:20 | access to local variable nonSink0 | LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:423:25:423:40 | SSA def(nonSink16) | LocalDataFlow.cs:424:19:424:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:427:17:427:22 | access to local variable sink70 | LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | -| LocalDataFlow.cs:429:18:429:30 | SSA def(sink72) | LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:435:17:435:24 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:437:18:437:33 | SSA def(nonSink17) | LocalDataFlow.cs:438:23:438:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | LocalDataFlow.cs:445:15:445:20 | access to local variable sink73 | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:22:443:29 | access to local variable nonSink0 | LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:443:22:443:38 | ... ?? ... | LocalDataFlow.cs:443:13:443:38 | SSA def(sink73) | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:443:22:443:38 | ... ?? ... | -| LocalDataFlow.cs:443:34:443:38 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | -| LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | LocalDataFlow.cs:446:15:446:20 | access to local variable sink74 | -| LocalDataFlow.cs:444:22:444:26 | access to local variable sink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:444:22:444:38 | ... ?? ... | LocalDataFlow.cs:444:13:444:38 | SSA def(sink74) | -| LocalDataFlow.cs:444:31:444:38 | access to local variable nonSink0 | LocalDataFlow.cs:444:22:444:38 | ... ?? ... | -| LocalDataFlow.cs:464:28:464:30 | this | LocalDataFlow.cs:464:41:464:45 | this access | -| LocalDataFlow.cs:464:50:464:52 | this | LocalDataFlow.cs:464:56:464:60 | this access | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:50:464:52 | value | -| LocalDataFlow.cs:464:50:464:52 | value | LocalDataFlow.cs:464:64:464:68 | access to parameter value | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:470:41:470:47 | tainted | -| LocalDataFlow.cs:470:41:470:47 | tainted | LocalDataFlow.cs:472:15:472:21 | access to parameter tainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:475:44:475:53 | nonTainted | -| LocalDataFlow.cs:475:44:475:53 | nonTainted | LocalDataFlow.cs:477:15:477:24 | access to parameter nonTainted | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:480:44:480:44 | x | -| LocalDataFlow.cs:480:44:480:44 | x | LocalDataFlow.cs:483:21:483:21 | access to parameter x | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:480:67:480:68 | os | -| LocalDataFlow.cs:480:67:480:68 | os | LocalDataFlow.cs:486:32:486:33 | access to parameter os | -| LocalDataFlow.cs:483:21:483:21 | access to parameter x | LocalDataFlow.cs:483:16:483:21 | ... = ... | -| LocalDataFlow.cs:486:32:486:33 | access to parameter os | LocalDataFlow.cs:486:26:486:33 | ... = ... | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:491:41:491:44 | args | -| LocalDataFlow.cs:491:41:491:44 | args | LocalDataFlow.cs:493:29:493:32 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | [post] access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:493:29:493:32 | call to operator implicit conversion | -| LocalDataFlow.cs:493:29:493:32 | access to parameter args | LocalDataFlow.cs:494:27:494:30 | access to parameter args | +| 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 | | 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:5:26:5:32 | tainted | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | -| SSA.cs:5:42:5:51 | nonTainted | SSA.cs:5:42:5:51 | nonTainted | | SSA.cs:5:42:5:51 | nonTainted | SSA.cs:12:24:12:33 | access to parameter nonTainted | | SSA.cs:8:13:8:30 | SSA def(ssaSink0) | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:8:24:8:30 | access to parameter tainted | SSA.cs:8:13:8:30 | SSA def(ssaSink0) | @@ -1032,7 +922,6 @@ | SSA.cs:136:23:136:28 | SSA def(this.S) | SSA.cs:137:15:137:20 | access to field S | | SSA.cs:136:23:136:28 | SSA qualifier def(this.S.SsaFieldNonSink0) | SSA.cs:137:15:137:37 | access to field SsaFieldNonSink0 | | SSA.cs:136:23:136:28 | access to field S | SSA.cs:136:23:136:28 | SSA def(this.S) | -| SSA.cs:144:34:144:34 | t | SSA.cs:144:34:144:34 | t | | SSA.cs:144:34:144:34 | t | SSA.cs:146:13:146:13 | access to parameter t | | SSA.cs:146:13:146:13 | (...) ... | SSA.cs:146:13:146:21 | ... == ... | | SSA.cs:146:13:146:13 | access to parameter t | SSA.cs:146:13:146:13 | (...) ... | @@ -1041,7 +930,6 @@ | SSA.cs:147:17:147:26 | default(...) | SSA.cs:147:13:147:26 | SSA def(t) | | SSA.cs:149:13:149:17 | SSA def(t) | SSA.cs:144:17:144:26 | SSA phi(t) | | SSA.cs:149:17:149:17 | access to parameter t | SSA.cs:149:13:149:17 | SSA def(t) | -| SSA.cs:152:36:152:36 | t | SSA.cs:152:36:152:36 | t | | SSA.cs:152:36:152:36 | t | SSA.cs:154:13:154:13 | access to parameter t | | SSA.cs:154:13:154:13 | (...) ... | SSA.cs:154:13:154:21 | ... == ... | | SSA.cs:154:13:154:13 | access to parameter t | SSA.cs:152:17:152:28 | SSA phi(t) | @@ -1050,9 +938,7 @@ | SSA.cs:155:25:155:25 | SSA def(t) | SSA.cs:152:17:152:28 | SSA phi(t) | | SSA.cs:155:25:155:25 | access to parameter t | SSA.cs:152:17:152:28 | SSA phi(t) | | SSA.cs:166:10:166:13 | this | SSA.cs:166:19:166:22 | this access | -| SSA.cs:168:22:168:28 | tainted | SSA.cs:168:22:168:28 | tainted | | SSA.cs:168:22:168:28 | tainted | SSA.cs:173:24:173:30 | access to parameter tainted | -| SSA.cs:168:35:168:35 | i | SSA.cs:168:35:168:35 | i | | SSA.cs:168:35:168:35 | i | SSA.cs:171:13:171:13 | access to parameter i | | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:170:27:170:28 | "" | SSA.cs:170:16:170:28 | SSA def(ssaSink5) | @@ -1069,9 +955,7 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | -| Splitting.cs:3:18:3:18 | b | Splitting.cs:3:18:3:18 | b | | Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | -| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:3:28:3:34 | tainted | | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | | Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | | Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | @@ -1084,7 +968,6 @@ | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | | Splitting.cs:12:15:12:15 | [post] [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | -| Splitting.cs:17:18:17:18 | b | Splitting.cs:17:18:17:18 | b | | Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | | Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | | Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | @@ -1097,7 +980,6 @@ | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | | Splitting.cs:25:15:25:15 | [post] [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | | Splitting.cs:25:15:25:15 | [post] [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | -| Splitting.cs:32:18:32:18 | b | Splitting.cs:32:18:32:18 | b | | Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | | Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | | Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | @@ -1118,7 +1000,6 @@ | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | | Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | | Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | -| Splitting.cs:46:18:46:18 | b | Splitting.cs:46:18:46:18 | b | | Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | | Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | | Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.cs b/csharp/ql/test/library-tests/dataflow/types/Types.cs index a768fc83135..9cb505004b7 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -114,6 +114,42 @@ class Types { Sink(this.Field); } + + void M10() + { + var a = new A(); + var e2 = new E2(); + Sink(Through(a)); // flow + Sink(Through(e2)); // flow + Sink((E2)Through(a)); // no flow + Sink((A)Through(e2)); // no flow + } } } + + 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 40e9c750a12..43b06fb7cba 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -32,13 +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 : 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 : 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 | @@ -82,27 +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 : 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 : 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: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 c5a0b98598f..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ /dev/null @@ -1,25 +0,0 @@ -missingOperand -unexpectedOperand -duplicateOperand -missingPhiOperand -missingOperandType -duplicateChiOperand -sideEffectWithoutPrimary -instructionWithoutSuccessor -ambiguousSuccessors -unexplainedLoop -unnecessaryPhiInstruction -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/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 48beeed5791..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 @@ -104,12 +103,12 @@ generates html slide shows in the ```` directory when run from the ``ql-training`` source directory. For more information about creating slides for QL training and variant analysis -examples, see the `template slide deck `__. +examples, see the `template slide deck `__. Viewing the current version of the CodeQL documentation ******************************************************* -The documentation for the most recent Semmle release is +The documentation for the most recent release is published to `help.semmle.com `__. There, you can also find the documentation for the CodeQL CLI, the CodeQL extension for Visual Studio Code, and LGTM Enterprise. diff --git a/docs/language/global-sphinx-files/qllexer.py b/docs/language/global-sphinx-files/qllexer.py index d31d4b0bf1f..33c0becdfc3 100644 --- a/docs/language/global-sphinx-files/qllexer.py +++ b/docs/language/global-sphinx-files/qllexer.py @@ -44,9 +44,9 @@ class QLLexer(RegexLexer): 'max', 'min', 'module', 'newtype', 'not', 'none', 'or', 'order', 'predicate', 'rank', 'result', 'select', 'strictconcat', 'strictcount', 'strictsum', 'sum', 'super', 'then', 'this', - 'true', 'where'), prefix=r'\b', suffix=r'\b'), + 'true', 'unique', 'where'), prefix=r'\b', suffix=r'\b'), Keyword), # Identifiers (r'@?\w', Name), ] - } \ No newline at end of file + } 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 2b12986ce94..c988fee9f9c 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -139,6 +139,10 @@ Global data flow Global data flow tracks data flow throughout the entire program, and is therefore more powerful than local data flow. However, global data flow is less precise than local data flow, and the analysis typically requires significantly more time and memory to perform. +.. pull-quote:: Note + + .. include:: ../../reusables/path-problem.rst + Using global data flow ~~~~~~~~~~~~~~~~~~~~~~ @@ -295,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 ------- @@ -389,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 c4b597428df..67414562893 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -137,6 +137,10 @@ Global data flow Global data flow tracks data flow throughout the entire program, and is therefore more powerful than local data flow. However, global data flow is less precise than local data flow, and the analysis typically requires significantly more time and memory to perform. +.. pull-quote:: Note + + .. include:: ../../reusables/path-problem.rst + Using global data flow ~~~~~~~~~~~~~~~~~~~~~~ @@ -549,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/database.rst b/docs/language/learn-ql/database.rst deleted file mode 100644 index 369b1d73fb0..00000000000 --- a/docs/language/learn-ql/database.rst +++ /dev/null @@ -1,33 +0,0 @@ -What's in a CodeQL database? -============================ - -A CodeQL database contains a variety of data related to a particular code base at a particular point in time. For details of how the database is generated see `Database generation `__ on LGTM.com. - -The database contains a full, hierarchical representation of the program defined by the code base. The database schema varies according to the language analyzed. The schema provides an interface between the initial lexical analysis during the extraction process, and the actual complex analysis using CodeQL. When the source code languages being analyzed change (such as Java 7 evolving into Java 8), this interface between the analysis phases can also change. - -For each language, a CodeQL library defines classes to provide a layer of abstraction over the database tables. This provides an object-oriented view of the data which makes it easier to write queries. This is easiest to explain using an example. - -Example -------- - -For a Java program, two key tables are: - -- The ``expressions`` table containing a row for every single expression in the source code that was analyzed during the build process. -- The ``statements`` table containing a row for every single statement in the source code that was analyzed during the build process. - -The CodeQL library defines classes to provide a layer of abstraction over each of these tables (and the related auxiliary tables): ``Expr`` and ``Stmt``. - -Most classes in the library are similar: they are abstractions over one or more database tables. Looking at one of the libraries illustrates this: - -.. code-block:: ql - - class Expr extends StmtParent, @expr { - ... - - /** the location of this expression */ - Location getLocation() { exprs(this,_,_,result) } - - ... - } - -The ``Expr`` class, shown here, extends from the database type ``@expr``. Member predicates of the ``Expr`` class are implemented in terms of the database-provided ``exprs`` table. 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 a0e04cf0370..9463dc04024 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -7,13 +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 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/index.rst b/docs/language/learn-ql/index.rst index e5617299436..0d979f7388a 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -3,7 +3,7 @@ Learning CodeQL CodeQL is the code analysis platform used by security researchers to automate variant analysis. You can use CodeQL queries to explore code and quickly find variants of security vulnerabilities and bugs. -These queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. +These queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. You can also try out CodeQL in the `query console on LGTM.com `__. Here, you can query open source projects directly, without having to download CodeQL databases and libraries. @@ -27,7 +27,6 @@ CodeQL is based on a powerful query language called QL. The following topics hel javascript/ql-for-javascript python/ql-for-python ql-training - technical-info .. toctree:: :hidden: 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..4591dc6aca1 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -240,6 +240,5 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress 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..d63f0ee3ac9 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -164,6 +164,5 @@ Finally, on many Java projects there are methods that are invoked indirectly by 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 d49128113ba..b8776548de9 100644 --- a/docs/language/learn-ql/java/dataflow.rst +++ b/docs/language/learn-ql/java/dataflow.rst @@ -147,6 +147,10 @@ Global data flow Global data flow tracks data flow throughout the entire program, and is therefore more powerful than local data flow. However, global data flow is less precise than local data flow, and the analysis typically requires significantly more time and memory to perform. +.. pull-quote:: Note + + .. include:: ../../reusables/path-problem.rst + Using global data flow ~~~~~~~~~~~~~~~~~~~~~~ @@ -253,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 ------- @@ -357,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..63092d005da 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 ------------- @@ -125,6 +125,5 @@ Now we rewrite our query to make use of these new classes: 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..cb89c178472 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 --------------------------------- @@ -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: @@ -386,6 +386,5 @@ For more information about callables and calls, see the :doc:`article on the cal 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..5039439212a 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -221,6 +221,5 @@ Currently, ``visibleIn`` only considers single-type imports, but you could exten 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..cba2881f740 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -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..c18adb65bf5 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -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[]``: @@ -299,6 +299,5 @@ Adding these three improvements, our final query becomes: 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 5009db4756a..53eb7b425f2 100644 --- a/docs/language/learn-ql/javascript/dataflow.rst +++ b/docs/language/learn-ql/javascript/dataflow.rst @@ -188,6 +188,10 @@ Global data flow tracks data flow throughout the entire program, and is therefor than local data flow. That is, the analysis may report spurious flows that cannot in fact happen. Moreover, global data flow analysis typically requires significantly more time and memory than local analysis. +.. pull-quote:: Note + + .. include:: ../../reusables/path-problem.rst + Using global data flow ~~~~~~~~~~~~~~~~~~~~~~ @@ -464,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 ------- @@ -553,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 c9aa0a241e6..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 `JavaScript 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 d0eac290a56..e3a9cc59135 100644 --- a/docs/language/learn-ql/ql-training.rst +++ b/docs/language/learn-ql/ql-training.rst @@ -32,7 +32,7 @@ We recommend that you download `CodeQL for Visual Studio Code `. -- 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/technical-info.rst b/docs/language/learn-ql/technical-info.rst deleted file mode 100644 index 7494011f7c6..00000000000 --- a/docs/language/learn-ql/technical-info.rst +++ /dev/null @@ -1,9 +0,0 @@ -Technical information -===================== - -.. toctree:: - :hidden: - - database - -- :doc:`What's in a CodeQL database? ` \ No newline at end of file diff --git a/docs/language/learn-ql/terminology-note.rst b/docs/language/learn-ql/terminology-note.rst index 552d7b2789c..211e4722112 100644 --- a/docs/language/learn-ql/terminology-note.rst +++ b/docs/language/learn-ql/terminology-note.rst @@ -18,10 +18,10 @@ Previously we used the term QL to refer to the whole code analysis platform, whi The name QL now only refers to the query language that powers CodeQL analysis. The CodeQL queries and libraries used to analyze source code are written in QL. -These queries and libraries are open source, and can be found in the `CodeQL repository `__. +These queries and libraries are open source, and can be found in the `CodeQL repository `__. QL is a general-purpose, object-oriented language that can be used to query any kind of data. CodeQL databases ---------------- -QL snapshots have been renamed CodeQL databases. :doc:`CodeQL databases ` contain relational data created and analyzed using CodeQL. They are the equivalent of QL snapshots, but have been optimized for use with the CodeQL tools. +QL snapshots have been renamed CodeQL databases. `CodeQL databases `__ contain relational data created and analyzed using CodeQL. They are the equivalent of QL snapshots, but have been optimized for use with the CodeQL tools. 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 fc17a2e8d36..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,21 +10,11 @@ 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. +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 `__. 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 `__. +For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. Basic query structure ********************* @@ -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 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. @@ -73,7 +62,7 @@ Import statements ================= Each query generally contains one or more ``import`` statements, which define the `libraries `__ or `modules `__ to import into the query. Libraries and modules provide a way of grouping together related `types `__, `predicates `__, and other modules. The contents of each library or module that you import can then be accessed by the query. -Our `open source repository on GitHub `__ contains the standard CodeQL libraries for each supported language. +Our `open source repository on GitHub `__ contains the standard CodeQL libraries for each supported language. When writing your own alert queries, you would typically import the standard library for the language of the project that you are querying, using ``import`` followed by a language: @@ -86,7 +75,7 @@ When writing your own alert queries, you would typically import the standard lib There are also libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. For more information, see :doc:`Creating path queries `. -You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__ or in the `GitHub repository `__. +You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__ or in the `GitHub repository `__. Optional CodeQL classes and predicates -------------------------------------- @@ -121,41 +110,25 @@ 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 *********************************** -One of the easiest ways to get started writing your own queries is to modify an existing query. To view the standard CodeQL queries, or to try out other examples, visit the `CodeQL `__ and `CodeQL for Go `__ repositories on GitHub. +One of the easiest ways to get started writing your own queries is to modify an existing query. To view the standard CodeQL queries, or to try out other examples, visit the `CodeQL `__ and `CodeQL for Go `__ repositories on GitHub. You can also find examples of queries developed to find security vulnerabilities and bugs in open source software projects on the `GitHub Security Lab website `__ and in the associated `repository `__. Contributing queries ******************** -Contributions to the standard queries and libraries are very welcome. For more information, see our `contributing guidelines `__. +Contributions to the standard queries and libraries are very welcome. For more information, see our `contributing guidelines `__. If you are contributing a query to the open source GitHub repository, writing a custom query for LGTM, or using a custom query in an analysis with the CodeQL CLI, then you need to include extra metadata in your query to ensure that the query results are interpreted and displayed correctly. See the following topics for more information on query metadata: - :doc:`Metadata for CodeQL queries ` -- `Query metadata style guide on GitHub `__ +- `Query metadata style guide on GitHub `__ -Query contributions to the open source GitHub repository may also have an accompanying query help file to provide information about their purpose for other users. For more information on writing query help, see the `Query help style guide on GitHub `__ and the :doc:`Query help files `. +Query contributions to the open source GitHub repository may also have an accompanying query help file to provide information about their purpose for other users. For more information on writing query help, see the `Query help style guide on GitHub `__ and the :doc:`Query help files `. 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 `__. +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 `. diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 41e9d0742eb..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 the queries included in the Semmle tools. -- 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 2bfc0db4b7e..04c04e405b8 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -4,7 +4,7 @@ Query help files Query help files tell users the purpose of a query, and recommend how to solve the potential problem the query finds. This topic provides detailed information on the structure of query help files. -For more information about how to write useful query help in a style that is consistent with the standard CodeQL queries, see the `Query help style guide `__ on GitHub. +For more information about how to write useful query help in a style that is consistent with the standard CodeQL queries, see the `Query help style guide `__ on GitHub. .. pull-quote:: @@ -12,8 +12,8 @@ For more information about how to write useful query help in a style that is con Note You can access the query help for CodeQL queries by visiting the `Built-in query pages `__. - You can also access the raw query help files in the `GitHub repository `__. - For example, see the `JavaScript security queries `__ and `C/C++ critical queries `__. + You can also access the raw query help files in the `GitHub repository `__. + For example, see the `JavaScript security queries `__ and `C/C++ critical queries `__. For queries run by default on LGTM, there are several different ways to access the query help. For further information, see `Where do I see the query help for a query on LGTM? `__ in the LGTM user help. @@ -63,7 +63,7 @@ Section-level elements are used to group the information in the help file into s +--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ | ``section`` | ``title`` Title of the section | Any block element | General-purpose section with a heading defined by the ``title`` attribute. | +--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``semmleNotes`` | None | Any block element | Semmle-specific notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. | +| ``semmleNotes`` | None | Any block element | Implementation notes about the query. This section is used only for queries that implement a rule defined by a third party. Default heading. | +--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ Block elements @@ -169,7 +169,7 @@ The ``include`` element can be used as a section or block element. The content Section-level include elements ------------------------------ -Section-level ``include`` elements can be located beneath the top-level ``qhelp`` element. For example, in `StoredXSS.qhelp `__, a full query help file is reused: +Section-level ``include`` elements can be located beneath the top-level ``qhelp`` element. For example, in `StoredXSS.qhelp `__, a full query help file is reused: .. code-block:: xml @@ -177,12 +177,12 @@ Section-level ``include`` elements can be located beneath the top-level ``qhelp` -In this example, the `XSS.qhelp `__ file must conform to the standard for a full query help file as described above. That is, the ``qhelp`` element may only contain non-``fragment``, section-level elements. +In this example, the `XSS.qhelp `__ file must conform to the standard for a full query help file as described above. That is, the ``qhelp`` element may only contain non-``fragment``, section-level elements. Block-level include elements ---------------------------- -Block-level ``include`` elements can be included beneath section-level elements. For example, an ``include`` element is used beneath the ``overview`` section in `ThreadUnsafeICryptoTransform.qhelp `__: +Block-level ``include`` elements can be included beneath section-level elements. For example, an ``include`` element is used beneath the ``overview`` section in `ThreadUnsafeICryptoTransform.qhelp `__: .. code-block:: xml @@ -193,7 +193,7 @@ Block-level ``include`` elements can be included beneath section-level elements. ... -The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `_, may only contain one or more ``fragment`` sections. For example: +The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `_, may only contain one or more ``fragment`` sections. For example: .. code-block:: xml @@ -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 362b3c54405..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. -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 `__. +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. .. 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 ---------------------------------------- @@ -98,8 +61,4 @@ 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 `__. - - - - +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/annotations.rst b/docs/language/ql-handbook/annotations.rst index 816b5ea5310..9177a4197b6 100644 --- a/docs/language/ql-handbook/annotations.rst +++ b/docs/language/ql-handbook/annotations.rst @@ -249,7 +249,7 @@ Compiler pragmas The following compiler pragmas affect the compilation and optimization of queries. You should avoid using these annotations unless you experience significant performance issues. -Before adding pragmas to your code, contact Semmle to describe the performance problems. +Before adding pragmas to your code, contact GitHub to describe the performance problems. That way we can suggest the best solution for your problem, and take it into account when improving the QL optimizer. @@ -292,7 +292,7 @@ optimization on a predicate. This kind of optimization involves taking information from the context of a predicate :ref:`call ` and pushing it into the body of a predicate. This is usually beneficial, so you shouldn't use the ``pragma[nomagic]`` annotation unless recommended to do so -by Semmle. +by GitHub. Note that ``nomagic`` implies ``noinline``. @@ -303,7 +303,7 @@ The ``pragma[noopt]`` annotation is used to prevent the QL optimizer from optimi predicate, except when it's absolutely necessary for compilation and evaluation to work. This is rarely necessary and you should not use the ``pragma[noopt]`` annotation unless -recommended to do so by Semmle, for example, to help resolve performance issues. +recommended to do so by GitHub, for example, to help resolve performance issues. When you use this annotation, be aware of the following issues: diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 5bb7370d11c..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. @@ -1002,7 +1071,7 @@ For casts between the primitive ``float`` and ``int`` types, the above rule mean Postfix casts ~~~~~~~~~~~~~ -*Available from Semmle 1.9.4 onward.* A postfix cast is a primary expression followed by a dot and then a class or primitive type in parentheses: +A postfix cast is a primary expression followed by a dot and then a class or primitive type in parentheses: :: @@ -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 92ac01bd42b..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: @@ -385,7 +386,7 @@ Algebraic datatypes ******************* .. note:: The syntax for algebraic datatypes is considered experimental and is subject to - change. However, they appear in the `standard QL libraries `_ + change. However, they appear in the `standard QL libraries `_ so the following sections should help you understand those examples. An algebraic datatype is another form of user-defined type, declared with the keyword ``newtype``. @@ -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 aaa2cd23d71..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 @@ -65,6 +65,6 @@ Entity types are rarely used directly, the usual pattern is to define a class th For example, the database schemas for C/++, C#, and Java CodeQL databases are here: - - https://github.com/Semmle/ql/blob/master/cpp/ql/src/semmlecode.cpp.dbscheme - - https://github.com/Semmle/ql/blob/master/csharp/ql/src/semmlecode.csharp.dbscheme - - https://github.com/Semmle/ql/blob/master/java/ql/src/config/semmlecode.dbscheme \ No newline at end of file + - https://github.com/github/codeql/blob/master/cpp/ql/src/semmlecode.cpp.dbscheme + - https://github.com/github/codeql/blob/master/csharp/ql/src/semmlecode.csharp.dbscheme + - https://github.com/github/codeql/blob/master/java/ql/src/config/semmlecode.dbscheme \ No newline at end of file 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 2dc64517465..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... @@ -101,11 +101,11 @@ Analysis overview .. note:: - Semmle’s analysis works by extracting a queryable database from your project. For compiled languages, Semmle’s tools observe an ordinary build of the source code. Each time a compiler is invoked to process a source file, a copy of that file is made, and all relevant information about the source code (syntactic data about the abstract syntax tree, semantic data like name binding and type information, data on the operation of the C preprocessor, etc.) is collected. For interpreted languages, the extractor gathers similar information by running directly on the source code. Multi-language code bases are analyzed one language at a time. + CodeQL analysis works by extracting a queryable database from your project. For compiled languages, the tools observe an ordinary build of the source code. Each time a compiler is invoked to process a source file, a copy of that file is made, and all relevant information about the source code (syntactic data about the abstract syntax tree, semantic data like name binding and type information, data on the operation of the C preprocessor, etc.) is collected. For interpreted languages, the extractor gathers similar information by running directly on the source code. Multi-language code bases are analyzed one language at a time. - Once the extraction finishes, all this information is collected into a single `CodeQL database `__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific. + Once the extraction finishes, all this information is collected into a single `CodeQL database `__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific. - Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries `__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine. + Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries `__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine. Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE extension `__ such as CodeQL for Visual Studio Code, or in a web dashboard as on `LGTM `__. @@ -129,7 +129,7 @@ QL is: - All common logic connectives are available, including quantifiers like ``exist``, which can also introduce new variables. - The language is declarative–the user focuses on stating what they would like to find, and leaves the details of how to evaluate the query to the engine. - - The object-oriented layer allows Semmle to distribute rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined. - - The database generated by Semmle’s tools is treated as read-only; queries cannot insert new data into it, though they can inspect its contents in various ways. + - The object-oriented layer allows us to develop rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined. + - The database generated by the CodeQL tools is treated as read-only; queries cannot insert new data into it, though they can inspect its contents in various ways. You can start writing running queries on open source projects in the `query console `__ on LGTM.com. You can also download CodeQL databases from LGTM.com to query locally, by `running queries in your IDE `__. 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/path-problem.rst b/docs/language/reusables/path-problem.rst new file mode 100644 index 00000000000..e3fe853874c --- /dev/null +++ b/docs/language/reusables/path-problem.rst @@ -0,0 +1 @@ +You can model data flow paths in CodeQL by creating path queries. To view data flow paths generated by a path query in CodeQL for VS Code, you need to make sure that it has the correct metadata and ``select`` clause. For more information, see `Creating path queries `__. \ No newline at end of file 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/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-style-guide.md b/docs/ql-style-guide.md index a22085f50b7..fba407ae8dd 100644 --- a/docs/ql-style-guide.md +++ b/docs/ql-style-guide.md @@ -3,7 +3,7 @@ ## Introduction This document describes how to format the code you contribute to this repository. It covers aspects such as layout, white-space, naming, and documentation. Adhering to consistent standards makes code easier to read and maintain. Of course, these are only guidelines, and can be overridden as the need arises on a case-by-case basis. Where existing code deviates from these guidelines, prefer consistency with the surrounding code. -Note, if you use CodeQL for VS Code, you can autoformat your query in the [Editor](https://help.semmle.com/codeql/codeql-for-vscode/reference/editor.html#autoformatting). +Note, if you use [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html), you can autoformat your query in the editor. Words in *italic* are defined in the [Glossary](#glossary). @@ -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..9ed8ee956b0 --- /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 c56cd885fce..f8584cb5e98 100644 --- a/docs/query-help-style-guide.md +++ b/docs/query-help-style-guide.md @@ -2,7 +2,7 @@ ## Introduction -When you contribute a new query to Semmle/ql for inclusion in the standard queries, or add a custom query for analysis in LGTM, you should also write a query help file. This file provides detailed information about the purpose and use of the query, which is available to users in LGTM (for example [here](https://lgtm.com/rules/1506093386171/)) and on the query homepages: +When you contribute a new [supported query](supported-queries.md) to this repository, or add a custom query for analysis in LGTM, you should also write a query help file. This file provides detailed information about the purpose and use of the query, which is available to users in LGTM (for example [here](https://lgtm.com/rules/1506093386171/)) and on the query homepages: * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) @@ -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 aba7df14849..1311a808e3a 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -11,22 +11,22 @@ 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) - * [CodeQL style guide](https://github.com/Semmle/ql/blob/master/docs/ql-style-guide.md) + * [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) For examples of query files for the languages supported by CodeQL, visit the following links: * [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/docs/supported-queries.md b/docs/supported-queries.md index 3ff2383ec01..dc02a1e547c 100644 --- a/docs/supported-queries.md +++ b/docs/supported-queries.md @@ -70,10 +70,11 @@ The process must begin with the first step and must conclude with the final step d. Provide one or more `@tags` describing the query. - - Tags are free-form, but we have some conventions, especially for tagging security queries with corresponding CWE numbers. + - Tags are free-form, but we have some conventions. At a minimum, most queries should have at least one of `correctness`, `maintainability` or `security` to indicate the general kind of issue the query is intended to find. Security queries should also be tagged with corresponding [CWE](https://cwe.mitre.org/data/definitions/1000.html) numbers, for example `external/cwe/cwe-119` (prefer the most specific CWE that encompasses the target of the query). 7. **Move your query out of `experimental`** - The structure of an `experimental` subdirectory mirrors the structure of its parent directory, so this step may just be a matter of removing the `experimental/` prefix of the query and test paths. Be sure to also edit any references to the query path in tests. - Add the query to one of the legacy suite files in `ql//config/suites//` if it exists. Note that there are separate suite directories for C and C++, `c` and `cpp` respectively, and the query should be added to one or both as appropriate. - Add a release note to `change-notes//analysis-.md`. + - Your pull request will be flagged automatically for a review by the documentation team to ensure that the query help file is ready for wider use. 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/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.java b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java new file mode 100644 index 00000000000..538620550ef --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java @@ -0,0 +1,22 @@ +@Configuration(proxyBeanMethods = false) +public class SpringBootActuators extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) -> + requests.anyRequest().permitAll()); + } +} + +@Configuration(proxyBeanMethods = false) +public class ActuatorSecurity extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) -> + requests.anyRequest().hasRole("ENDPOINT_ADMIN")); + http.httpBasic(); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp new file mode 100644 index 00000000000..53ee653aaff --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp @@ -0,0 +1,39 @@ + + + +

    Spring Boot includes a number of additional features called actuators that let you monitor +and interact with your web application. Exposing unprotected actuator endpoints via JXM or HTTP +can, however, lead to information disclosure or even to remote code execution vulnerability.

    +
    + + +

    Since actuator endpoints may contain sensitive information, careful consideration should be +given about when to expose them. You should take care to secure exposed HTTP endpoints in the same +way that you would any other sensitive URL. If Spring Security is present, endpoints are secured by +default using Spring Security’s content-negotiation strategy. If you wish to configure custom +security for HTTP endpoints, for example, only allow users with a certain role to access them, +Spring Boot provides some convenient RequestMatcher objects that can be used in +combination with Spring Security.

    +
    + + +

    In the first example, the custom security configuration allows unauthenticated access to all +actuator endpoints. This may lead to sensitive information disclosure and should be avoided.

    +

    In the second example, only users with ENDPOINT_ADMIN role are allowed to access +the actuator endpoints.

    + + +
    + + +
  • +Spring Boot documentation: +Actuators. +
  • +
  • +Exploiting Spring Boot Actuators +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql new file mode 100644 index 00000000000..85daa77cc56 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql @@ -0,0 +1,18 @@ +/** + * @name Exposed Spring Boot actuators + * @description Exposing Spring Boot actuators may lead to internal application's information leak + * or even to remote code execution. + * @kind problem + * @problem.severity error + * @precision high + * @id java/spring-boot-exposed-actuators + * @tags security + * external/cwe/cwe-16 + */ + +import java +import SpringBootActuators + +from PermitAllCall permitAllCall +where permitAllCall.permitsSpringBootActuators() +select permitAllCall, "Unauthenticated access to Spring Boot actuator is allowed." diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll new file mode 100644 index 00000000000..c1ef873b1fa --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -0,0 +1,159 @@ +import java + +/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */ +class TypeHttpSecurity extends Class { + TypeHttpSecurity() { + this + .hasQualifiedName("org.springframework.security.config.annotation.web.builders", + "HttpSecurity") + } +} + +/** + * The class + * `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer`. + */ +class TypeAuthorizedUrl extends Class { + TypeAuthorizedUrl() { + this + .hasQualifiedName("org.springframework.security.config.annotation.web.configurers", + "ExpressionUrlAuthorizationConfigurer$AuthorizedUrl<>") + } +} + +/** + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + */ +class TypeAbstractRequestMatcherRegistry extends Class { + TypeAbstractRequestMatcherRegistry() { + this + .hasQualifiedName("org.springframework.security.config.annotation.web", + "AbstractRequestMatcherRegistry>") + } +} + +/** + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. + */ +class TypeEndpointRequest extends Class { + TypeEndpointRequest() { + this + .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", + "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 `RequestMatcher.toAnyEndpoint()`. + */ +class RequestMatcherCall extends MethodAccess { + RequestMatcherCall() { + getMethod().hasName("requestMatcher") and + getMethod().getDeclaringType() instanceof TypeHttpSecurity and + getArgument(0) instanceof ToAnyEndpointCall + } +} + +/** + * 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() instanceof ToAnyEndpointCall + } +} + +/** A call to `HttpSecurity.authorizeRequests` method. */ +class AuthorizeRequestsCall extends MethodAccess { + AuthorizeRequestsCall() { + getMethod().hasName("authorizeRequests") and + getMethod().getDeclaringType() instanceof TypeHttpSecurity + } +} + +/** A call to `AuthorizedUrl.permitAll` method. */ +class PermitAllCall extends MethodAccess { + PermitAllCall() { + getMethod().hasName("permitAll") and + getMethod().getDeclaringType() instanceof TypeAuthorizedUrl + } + + /** Holds if `permitAll` is called on request(s) mapped to actuator endpoint(s). */ + predicate permitsSpringBootActuators() { + exists(AuthorizeRequestsCall authorizeRequestsCall | + // .requestMatcher(EndpointRequest).authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof RequestMatcherCall + or + // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall + | + // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and + ( + this.getQualifier() instanceof AnyRequestCall or + this.getQualifier() instanceof RegistryRequestMatchersCall + ) + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + // [...].authorizeRequests().anyRequest().permitAll() + authorizeRequestsCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and + this.getQualifier() = registryRequestMatchersCall + ) + or + exists(AnyRequestCall anyRequestCall | + anyRequestCall.getQualifier() = authorizeRequestsCall and + 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 + ) + ) + } +} + +/** A call to `AbstractRequestMatcherRegistry.anyRequest` method. */ +class AnyRequestCall extends MethodAccess { + AnyRequestCall() { + getMethod().hasName("anyRequest") and + getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry + } +} + +/** + * 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() 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-1004/InsecureTomcatConfig.qhelp b/java/ql/src/experimental/Security/CWE/CWE-1004/InsecureTomcatConfig.qhelp new file mode 100644 index 00000000000..842402e9252 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/InsecureTomcatConfig.qhelp @@ -0,0 +1,35 @@ + + + + +

    When you add an application to a Tomcat server, it will generate a new JSESSIONID when you call request.getSession() +or if you invoke a JSP from a servlet. If cookies are generated without the HttpOnly flag, +an attacker can use a cross-site scripting (XSS) attack to get another user's session ID. +

    +
    + + +

    Tomcat version 7+ automatically sets an HttpOnly flag on all session cookies to +prevent client side scripts from accessing the session ID. +In most situations, you should not override this behavior.

    +
    + + +

    The following example shows a Tomcat configuration with useHttpOnly disabled. Usually you should not set this.

    + + +
    + + +
  • +CWE: +Sensitive Cookie Without 'HttpOnly' Flag. +
  • +
  • +OWASP: + + HttpOnly +. +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/InsecureTomcatConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-1004/InsecureTomcatConfig.ql new file mode 100644 index 00000000000..3f165ecb627 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/InsecureTomcatConfig.ql @@ -0,0 +1,26 @@ +/** + * @name Tomcat config disables 'HttpOnly' flag (XSS risk) + * @description Disabling 'HttpOnly' leaves session cookies vulnerable to an XSS attack. + * @kind problem + * @problem.severity warning + * @precision medium + * @id java/tomcat-disabled-httponly + * @tags security + * external/cwe/cwe-1004 + */ + +import java +import semmle.code.xml.WebXML + +private class HttpOnlyConfig extends WebContextParameter { + HttpOnlyConfig() { this.getParamName().getValue() = "useHttpOnly" } + + string getParamValueElementValue() { result = getParamValue().getValue() } + + predicate isHTTPOnlySet() { getParamValueElementValue().toLowerCase() = "false" } +} + +from HttpOnlyConfig config +where config.isHTTPOnlySet() +select config, + "httpOnly should be enabled in tomcat config file to help mitigate cross-site scripting (XSS) attacks" diff --git a/java/ql/src/experimental/Security/CWE/CWE-1004/insecure-web.xml b/java/ql/src/experimental/Security/CWE/CWE-1004/insecure-web.xml new file mode 100644 index 00000000000..2140acc2844 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-1004/insecure-web.xml @@ -0,0 +1,9 @@ + + Sample Tomcat Web Application + + useHttpOnly + false + + \ No newline at end of file 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-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..4e21e743695 --- /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 fro `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/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/java/Collections.qll b/java/ql/src/semmle/code/java/Collections.qll index b0cf771778d..9569dfc4c2c 100644 --- a/java/ql/src/semmle/code/java/Collections.qll +++ b/java/ql/src/semmle/code/java/Collections.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about instances of + * `java.util.Collection` and their methods. + */ + import java /** @@ -77,6 +82,7 @@ class CollectionMutator extends CollectionMethod { class CollectionMutation extends MethodAccess { CollectionMutation() { this.getMethod() instanceof CollectionMutator } + /** Holds if the result of this call is not immediately discarded. */ predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } } diff --git a/java/ql/src/semmle/code/java/Completion.qll b/java/ql/src/semmle/code/java/Completion.qll index c8b4f966a3b..6ccdb16df72 100644 --- a/java/ql/src/semmle/code/java/Completion.qll +++ b/java/ql/src/semmle/code/java/Completion.qll @@ -68,21 +68,27 @@ newtype Completion = */ ThrowCompletion(ThrowableType tt) +/** A completion that is either a `NormalCompletion` or a `BooleanCompletion`. */ class NormalOrBooleanCompletion extends Completion { NormalOrBooleanCompletion() { this instanceof NormalCompletion or this instanceof BooleanCompletion } + /** Gets a textual representation of this completion. */ string toString() { result = "completion" } } +/** Gets the completion `ContinueCompletion(NoLabel())`. */ ContinueCompletion anonymousContinueCompletion() { result = ContinueCompletion(NoLabel()) } +/** Gets the completion `ContinueCompletion(JustLabel(l))`. */ ContinueCompletion labelledContinueCompletion(Label l) { result = ContinueCompletion(JustLabel(l)) } +/** Gets the completion `BreakCompletion(NoLabel())`. */ BreakCompletion anonymousBreakCompletion() { result = BreakCompletion(NoLabel()) } +/** Gets the completion `BreakCompletion(JustLabel(l))`. */ BreakCompletion labelledBreakCompletion(Label l) { result = BreakCompletion(JustLabel(l)) } -/** Gets the completion `booleanCompletion(value, value)`. */ +/** Gets the completion `BooleanCompletion(value, value)`. */ Completion basicBooleanCompletion(boolean value) { result = BooleanCompletion(value, value) } diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index 13e6524352a..f482398a74f 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -113,6 +113,7 @@ class ControlFlowNode extends Top, @exprparent { result = succ(this, NormalCompletion()) } + /** Gets the basic block that contains this node. */ BasicBlock getBasicBlock() { result.getANode() = this } } @@ -404,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 @@ -428,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 @@ -572,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 } /** @@ -704,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 @@ -913,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 73475f6cc70..c175894588c 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -305,10 +305,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 +328,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 +412,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 @@ -844,6 +843,7 @@ class EqualityTest extends BinaryExpr { this instanceof NEExpr } + /** Gets a boolean indicating whether this is `==` (true) or `!=` (false). */ boolean polarity() { result = true and this instanceof EQExpr or @@ -1050,6 +1050,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`, diff --git a/java/ql/src/semmle/code/java/Maps.qll b/java/ql/src/semmle/code/java/Maps.qll index 6a681e60683..c86cb0ef47a 100644 --- a/java/ql/src/semmle/code/java/Maps.qll +++ b/java/ql/src/semmle/code/java/Maps.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about instances of + * `java.util.Map` and their methods. + */ + import java import Collections @@ -47,6 +52,7 @@ class MapSizeMethod extends MapMethod { class MapMutation extends MethodAccess { MapMutation() { this.getMethod() instanceof MapMutator } + /** Holds if the result of this call is not immediately discarded. */ predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } } @@ -72,7 +78,9 @@ class FreshMap extends ClassInstanceExpr { class MapPutCall extends MethodAccess { MapPutCall() { getCallee().(MapMethod).hasName("put") } + /** Gets the key argument of this call. */ Expr getKey() { result = getArgument(0) } + /** Gets the value argument of this call. */ Expr getValue() { result = getArgument(1) } } 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/Reflection.qll b/java/ql/src/semmle/code/java/Reflection.qll index 3b0189e17ae..5a46fcb8be2 100644 --- a/java/ql/src/semmle/code/java/Reflection.qll +++ b/java/ql/src/semmle/code/java/Reflection.qll @@ -7,12 +7,14 @@ import JDKAnnotations import Serializability import semmle.code.java.dataflow.DefUse +/** Holds if `f` is a field that may be read by reflection. */ predicate reflectivelyRead(Field f) { f instanceof SerializableField or f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or referencedInXmlFile(f) } +/** Holds if `f` is a field that may be written by reflection. */ predicate reflectivelyWritten(Field f) { f instanceof DeserializableField or f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or @@ -360,6 +362,7 @@ class ReflectiveFieldAccess extends ClassMethodAccess { this.getCallee().hasName("getDeclaredField") } + /** Gets the field accessed by this call. */ Field inferAccessedField() { ( if this.getCallee().hasName("getDeclaredField") 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 410d83818cc..fac84c5c8af 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -80,6 +80,7 @@ private newtype TFmtSyntax = /** A syntax for format strings. */ class FmtSyntax extends TFmtSyntax { + /** Gets a textual representation of this format string syntax. */ string toString() { result = "printf (%) syntax" and this = TFmtPrintf() or @@ -130,6 +131,7 @@ class FormattingCall extends Call { formatWrapper(this.getCallee(), result, _) } + /** Gets the format string syntax used by this call. */ FmtSyntax getSyntax() { this.getCallee() instanceof StringFormatMethod and result = TFmtPrintf() or @@ -146,6 +148,7 @@ class FormattingCall extends Call { ) } + /** Holds if this uses the "logger ({})" format syntax and the last argument is a `Throwable`. */ predicate hasTrailingThrowableArgument() { getSyntax() = TFmtLogger() and getLastArg().getType().(RefType).getASourceSupertype*() instanceof TypeThrowable @@ -245,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 ) } @@ -290,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/Type.qll b/java/ql/src/semmle/code/java/Type.qll index 35f35d44928..4f29ea94bd7 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -637,10 +637,12 @@ class IntersectionType extends RefType, @class { private RefType superInterface() { implInterface(this, result) } + /** Gets a textual representation of this type that includes all the intersected types. */ string getLongName() { result = superType().toString() + concat(" & " + superInterface().toString()) } + /** Gets the first bound of this intersection type. */ RefType getFirstBound() { extendsReftype(this, result) } } diff --git a/java/ql/src/semmle/code/java/controlflow/Guards.qll b/java/ql/src/semmle/code/java/controlflow/Guards.qll index 82cb1d997ae..0d18ac24e51 100644 --- a/java/ql/src/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/src/semmle/code/java/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 java private import semmle.code.java.controlflow.Dominance private import semmle.code.java.controlflow.internal.GuardsLogic 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/Bound.qll b/java/ql/src/semmle/code/java/dataflow/Bound.qll index 1742e1dc4fe..4a89f8cfeba 100644 --- a/java/ql/src/semmle/code/java/dataflow/Bound.qll +++ b/java/ql/src/semmle/code/java/dataflow/Bound.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for representing abstract bounds for use in, for example, range analysis. + */ + import java private import SSA private import RangeUtils @@ -14,6 +18,7 @@ private newtype TBound = * A bound that may be inferred for an expression plus/minus an integer delta. */ abstract class Bound extends TBound { + /** Gets a textual representation of this bound. */ abstract string toString(); /** Gets an expression that equals this bound plus `delta`. */ @@ -22,6 +27,13 @@ abstract class Bound extends TBound { /** Gets an expression that equals this bound. */ Expr getExpr() { result = getExpr(0) } + /** + * Holds if this element is at the specified location. + * The location spans column `sc` of line `sl` to + * column `ec` of line `el` in file `path`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ 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 } diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index e8872e1bdfb..7996a6d3142 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -103,6 +103,19 @@ private class MessageBodyReaderParameterSource extends RemoteFlowSource { override string getSourceType() { result = "MessageBodyReader parameter" } } +private class SpringMultipartFileSource extends RemoteFlowSource { + SpringMultipartFileSource() { + exists(MethodAccess ma, Method m | + ma = this.asExpr() and + m = ma.getMethod() and + m.getDeclaringType().hasQualifiedName("org.springframework.web.multipart", "MultipartFile") and + m.getName().matches("get%") + ) + } + + override string getSourceType() { result = "Spring MultipartFile getter" } +} + private class SpringServletInputParameterSource extends RemoteFlowSource { SpringServletInputParameterSource() { this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation @@ -152,9 +165,13 @@ deprecated class RemoteUserInput extends UserInput { RemoteUserInput() { this instanceof RemoteFlowSource } } -/** Input that may be controlled by a local user. */ +/** A node with input that may be controlled by a local user. */ abstract class LocalUserInput extends UserInput { } +/** + * A node with input from the local environment, such as files, standard in, + * environment variables, and main method parameters. + */ class EnvInput extends LocalUserInput { EnvInput() { // Parameters to a main method. @@ -180,6 +197,7 @@ class EnvInput extends LocalUserInput { } } +/** A node with input from a database. */ class DatabaseInput extends LocalUserInput { DatabaseInput() { this.asExpr().(MethodAccess).getMethod() instanceof ResultSetGetStringMethod } } @@ -222,10 +240,12 @@ private class EnvTaintedMethod extends Method { } } +/** The type `java.net.InetAddress`. */ class TypeInetAddr extends RefType { TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" } } +/** A reverse DNS method. */ class ReverseDNSMethod extends Method { ReverseDNSMethod() { this.getDeclaringType() instanceof TypeInetAddr and 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 644790bea6b..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 @@ -579,7 +576,7 @@ private predicate varMaybeNullInBlock_corrCond( * - int: A means a specific integer value and B means any other value. */ -newtype TrackVarKind = +private newtype TrackVarKind = TrackVarKindNull() or TrackVarKindBool() or TrackVarKindEnum() or @@ -701,7 +698,7 @@ private predicate isReset( } /** The abstract value of the tracked variable. */ -newtype TrackedValue = +private newtype TrackedValue = TrackedValueA() or TrackedValueB() or TrackedValueUnknown() diff --git a/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll index 435b976fde2..607ce04da80 100644 --- a/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll +++ b/java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll @@ -264,14 +264,21 @@ private newtype TReason = * without going through a bounding condition. */ abstract class Reason extends TReason { + /** Gets a textual representation of this reason. */ abstract string toString(); } +/** + * A reason for an inferred bound that indicates that the bound is inferred + * without going through a bounding condition. + */ class NoReason extends Reason, TNoReason { override string toString() { result = "NoReason" } } +/** A reason for an inferred bound pointing to a condition. */ class CondReason extends Reason, TCondReason { + /** Gets the condition that is the reason for the bound. */ Guard getCond() { this = TCondReason(result) } override string toString() { result = getCond().toString() } diff --git a/java/ql/src/semmle/code/java/dataflow/RangeUtils.qll b/java/ql/src/semmle/code/java/dataflow/RangeUtils.qll index 22e363d9e3c..e7da9891b47 100644 --- a/java/ql/src/semmle/code/java/dataflow/RangeUtils.qll +++ b/java/ql/src/semmle/code/java/dataflow/RangeUtils.qll @@ -142,6 +142,7 @@ class SsaReadPosition extends TSsaReadPosition { /** Holds if `v` is read at this position. */ abstract predicate hasReadOfVar(SsaVariable v); + /** Gets a textual representation of this SSA read position. */ abstract string toString(); } diff --git a/java/ql/src/semmle/code/java/dataflow/SSA.qll b/java/ql/src/semmle/code/java/dataflow/SSA.qll index 561fdb35c5e..e6d92bb4d60 100644 --- a/java/ql/src/semmle/code/java/dataflow/SSA.qll +++ b/java/ql/src/semmle/code/java/dataflow/SSA.qll @@ -89,6 +89,7 @@ class SsaSourceVariable extends TSsaSourceVariable { this = TQualifiedField(result, _, _) } + /** Gets a textual representation of this `SsaSourceVariable`. */ string toString() { exists(LocalScopeVariable v, Callable c | this = TLocalVar(c, v) | if c = v.getCallable() @@ -112,6 +113,7 @@ class SsaSourceVariable extends TSsaSourceVariable { ) } + /** Gets the source location for this element. */ Location getLocation() { exists(LocalScopeVariable v | this = TLocalVar(_, v) and result = v.getLocation()) or @@ -935,8 +937,10 @@ class SsaVariable extends TSsaVariable { this = TSsaUntracked(_, result) } + /** Gets a textual representation of this SSA variable. */ string toString() { none() } + /** Gets the source location for this element. */ Location getLocation() { result = getCFGNode().getLocation() } /** Gets the `BasicBlock` in which this SSA variable is defined. */ @@ -1113,7 +1117,7 @@ class SsaPhiNode extends SsaVariable, TSsaPhiNode { } } -library class RefTypeCastExpr extends CastExpr { +private class RefTypeCastExpr extends CastExpr { RefTypeCastExpr() { this.getType() instanceof RefType } } 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 24cf918a9b7..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() @@ -365,12 +378,12 @@ private predicate typeFlow(TypeFlowNode n, RefType t) { } pragma[nomagic] -predicate erasedTypeBound(RefType t) { +private predicate erasedTypeBound(RefType t) { exists(RefType t0 | typeFlow(_, t0) and t = t0.getErasure()) } pragma[nomagic] -predicate typeBound(RefType t) { typeFlow(_, t) } +private predicate typeBound(RefType t) { typeFlow(_, t) } /** * Holds if we have a bound for `n` that is better than `t`, taking only erased 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 a1daeb66411..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 a1daeb66411..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -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() } @@ -251,15 +248,11 @@ private predicate additionalJumpStep(Node node1, Node node2, Configuration confi */ private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } -pragma[noinline] -private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { - viableCallable(call) = result.getCallable() and - kind = result.getKind() -} - /** - * Holds if `node` is reachable from a source in the given configuration - * taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. */ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { not fullBarrier(node, config) and @@ -293,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - storeDirect(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - storeCandFwd1(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -317,13 +310,35 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) fromArg = false or nodeCandFwd1OutFromArg(call, node, config) and - flowOutCandFwd1(call, fromArg, config) + nodeCandFwd1IsEntered(call, fromArg, config) ) ) } private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } +pragma[nomagic] +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, c, node) + ) +} + +/** + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +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, tc, node, _) and + c = tc.getContent() + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +350,10 @@ private predicate nodeCandFwd1ReturnPosition( } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { - exists(Node mid | - nodeCandFwd1(mid, fromArg, config) and - readDirect(mid, f, node) - ) -} - -/** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. - */ -pragma[nomagic] -private predicate storeCandFwd1(Content f, Configuration config) { - exists(Node mid, Node node | - not fullBarrier(node, config) and - useFieldFlow(config) and - nodeCandFwd1(mid, config) and - storeDirect(mid, f, node) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1ReturnKind( - DataFlowCall call, ReturnKindExt kind, boolean fromArg, Configuration config -) { +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { exists(ReturnPosition pos | nodeCandFwd1ReturnPosition(pos, fromArg, config) and - pos = viableReturnPos(call, kind) - ) -} - -pragma[nomagic] -private predicate nodeCandFwd1Out( - DataFlowCall call, Node node, boolean fromArg, Configuration config -) { - exists(ReturnKindExt kind | - nodeCandFwd1ReturnKind(call, kind, fromArg, config) and - node = kind.getAnOutNode(call) + viableReturnPosOut(call, pos, out) ) } @@ -384,7 +366,7 @@ private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configura * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate flowOutCandFwd1(DataFlowCall call, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { exists(ArgumentNode arg | nodeCandFwd1(arg, fromArg, config) and viableParamArg(call, _, arg) @@ -395,8 +377,11 @@ bindingset[result, b] private boolean unbindBool(boolean b) { result != b.booleanNot() } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. */ pragma[nomagic] private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { @@ -433,81 +418,86 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or // flow into a callable exists(DataFlowCall call | - nodeCand1Arg(call, node, false, config) and + nodeCand1In(call, node, false, config) and toReturn = false or - nodeCand1ArgToReturn(call, node, config) and - flowInCand1(call, toReturn, config) + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) ) or // flow out of a callable exists(ReturnPosition pos | - nodeCand1ReturnPosition(pos, config) and + nodeCand1Out(pos, config) and getReturnPosition(node) = pos and toReturn = true ) } -pragma[nomagic] -private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } - -pragma[nomagic] -private predicate nodeCand1ReturnPosition(ReturnPosition pos, Configuration config) { - exists(DataFlowCall call, ReturnKindExt kind, Node out | - nodeCand1(out, _, config) and - pos = viableReturnPos(call, kind) and - out = kind.getAnOutNode(call) - ) -} - /** - * 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 readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + 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 - storeCandFwd1(f, unbind(config)) and - storeDirect(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 readStoreCand1(Content f, Configuration conf) { - readCand1(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] -private predicate viableParamArgCandFwd1( +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config ) { viableParamArg(call, p, arg) and @@ -515,32 +505,35 @@ private predicate viableParamArgCandFwd1( } pragma[nomagic] -private predicate nodeCand1Arg( +private predicate nodeCand1In( DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config ) { exists(ParameterNode p | nodeCand1(p, toReturn, config) and - viableParamArgCandFwd1(call, p, arg, config) + viableParamArgNodeCandFwd1(call, p, arg, config) ) } pragma[nomagic] -private predicate nodeCand1ArgToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { - nodeCand1Arg(call, arg, true, config) +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) } /** * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate flowInCand1(DataFlowCall call, boolean toReturn, Configuration config) { +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { exists(Node out | nodeCand1(out, toReturn, config) and nodeCandFwd1OutFromArg(call, out, config) ) } -private predicate throughFlowNodeCand(Node node, Configuration config) { +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { nodeCand1(node, true, config) and not fullBarrier(node, config) and not inBarrier(node, config) and @@ -549,11 +542,11 @@ private predicate throughFlowNodeCand(Node node, Configuration config) { /** Holds if flow may return from `callable`. */ pragma[nomagic] -private predicate returnFlowCallableCand( +private predicate returnFlowCallableNodeCand1( DataFlowCallable callable, ReturnKindExt kind, Configuration config ) { exists(ReturnNodeExt ret | - throughFlowNodeCand(ret, config) and + throughFlowNodeCand1(ret, config) and callable = ret.getEnclosingCallable() and kind = ret.getKind() ) @@ -563,10 +556,10 @@ private predicate returnFlowCallableCand( * Holds if flow may enter through `p` and reach a return node making `p` a * candidate for the origin of a summary. */ -private predicate parameterThroughFlowCand(ParameterNode p, Configuration config) { +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { exists(ReturnKindExt kind | - throughFlowNodeCand(p, config) and - returnFlowCallableCand(p.getEnclosingCallable(), kind, config) and + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and // we don't expect a parameter to return stored in itself not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) @@ -575,420 +568,77 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) -} - -pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and - nodeCand1(n2, unbind(config)) and - ( - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) - ) -} - -/** - * Holds if `p` can flow to `node` in the same callable with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -pragma[nomagic] -private predicate parameterFlow( - ParameterNode p, Node node, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - parameterThroughFlowCand(p, config) and - p = node and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = TSummaryVal() - or - throughFlowNodeCand(node, unbind(config)) and - ( - exists(Node mid | - parameterFlow(p, mid, t1, t2, summary, config) and - localFlowStep(mid, node, config) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - exists(Node mid, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - additionalLocalFlowStep(mid, node, config) and - t1 = getErasedNodeTypeBound(node) and - t1 = t2 and - summary = midsum.additionalStep() - ) - or - // read step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, _, _, midsum, config) and - read(mid, f, node, config) and - summary = midsum.readStep(f) and - t1 = f.getType() and - t1 = t2 - ) - or - // store step - exists(Node mid, Content f, Summary midsum | - parameterFlow(p, mid, t1, /* t1 */ _, midsum, config) and - store(mid, f, node, config) and - summary = midsum.storeStep(f) and - compatibleTypes(t1, f.getType()) and - t2 = f.getContainerType() - ) - or - // value flow through a callable - exists(Node arg | - parameterFlow(p, arg, t1, t2, summary, config) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) and - compatibleTypes(t2, getErasedNodeTypeBound(node)) - ) - or - // flow through a callable - exists(Node arg, Summary s1, Summary s2 | - parameterFlow(p, arg, _, _, s1, config) and - argumentFlowsThrough(arg, node, t1, t2, s2, config) and - summary = s1.compose(s2) - ) - ) -} - -private predicate viableParamArgCand( - DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config -) { - viableParamArg(call, p, arg) and - nodeCand1(arg, unbind(config)) and - nodeCand1(p, config) and - not outBarrier(arg, config) and - not inBarrier(p, config) -} - -pragma[nomagic] -private predicate parameterFlowReturn( - ParameterNode p, ReturnNodeExt ret, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - parameterFlow(p, ret, t1, t2, summary, config) and - kind = ret.getKind() and - not summary.isPartial() and - not exists(int pos | kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos)) -} - -pragma[nomagic] -private predicate argumentFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, DataFlowType t1, DataFlowType t2, - Summary summary, Configuration config -) { - exists(ParameterNode p | - viableParamArgCand(call, p, arg, config) and - parameterFlowReturn(p, _, kind, t1, t2, summary, config) - ) -} - -/** - * Holds if data can flow from `arg` to `out` through a call with `summary` - * representing the flow path. The type of the tracked object is `t2`, and if - * the summary includes a store step, `t1` is the tracked type just prior to the - * store, that is, the type of the stored object, otherwise `t1` is equal to `t2`. - */ -private predicate argumentFlowsThrough( - ArgumentNode arg, Node out, DataFlowType t1, DataFlowType t2, Summary summary, - Configuration config -) { - nodeCand1(out, unbind(config)) and - not inBarrier(out, config) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - exists(DataFlowCall call, ReturnKindExt kind | - argumentFlowsThrough0(call, arg, kind, t1, t2, summary, config) and - out = kind.getAnOutNode(call) - ) -} - -pragma[noinline] -private predicate readStoreNode( - DataFlowCall call, ArgumentNode arg, Content f1, Configuration config -) { - exists(Content f2, Node out | - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f2), out) and - nodeCand1(out, config) and - readStoreCand1(f2, unbind(config)) - ) -} - -private newtype TNodeExt = - TNormalNode(Node node) { nodeCand1(node, _) } or - TReadStoreNode(DataFlowCall call, ArgumentNode arg, Content f1, Configuration config) { - nodeCand1(arg, config) and - readStoreNode(call, arg, f1, config) and - readStoreCand1(f1, unbind(config)) - } or - TReadTaintNode(ArgumentNode arg, Content f, Configuration config) { - argumentFlowsThrough(arg, _, _, _, TSummaryReadTaint(f), config) - } or - TTaintStoreNode(ArgumentNode arg, DataFlowType t, Configuration config) { - argumentFlowsThrough(arg, _, t, _, TSummaryTaintStore(_), config) - } - -/** - * An extended data flow node. Either a normal node, or an intermediate node - * used to split up a summarized flow steps. - * - * This is purely an internal implementation detail. - */ -abstract private class NodeExt extends TNodeExt { - /** Gets the underlying (normal) node, if any. */ - abstract Node getNode(); - - abstract DataFlowType getErasedNodeTypeBound(); - - abstract DataFlowCallable getEnclosingCallable(); - - abstract predicate isCand1(Configuration config); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A `Node` at which a cast can occur such that the type should be checked. */ -abstract private class CastingNodeExt extends NodeExt { } - -private class NormalNodeExt extends NodeExt, TNormalNode { - override Node getNode() { this = TNormalNode(result) } - - override DataFlowType getErasedNodeTypeBound() { - result = getErasedRepr(this.getNode().getTypeBound()) - } - - override DataFlowCallable getEnclosingCallable() { - result = this.getNode().getEnclosingCallable() - } - - override predicate isCand1(Configuration config) { nodeCand1(this.getNode(), config) } - - override string toString() { result = this.getNode().toString() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class NormalCastingNodeExt extends CastingNodeExt, NormalNodeExt { - NormalCastingNodeExt() { this.getNode() instanceof CastingNode } -} - -private class ReadStoreNodeExt extends CastingNodeExt, TReadStoreNode { - private DataFlowCall call; - private ArgumentNode arg; - private Content f1; - private Configuration config0; - - ReadStoreNodeExt() { this = TReadStoreNode(call, arg, f1, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f1.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = "(inside) " + call.toString() + " [read " + f1 + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class ReadTaintNode extends NodeExt, TReadTaintNode { - private ArgumentNode arg; - private Content f; - private Configuration config0; - - ReadTaintNode() { this = TReadTaintNode(arg, f, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = f.getType() } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [read taint " + f + "]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private class TaintStoreNode extends NodeExt, TTaintStoreNode { - private ArgumentNode arg; - private DataFlowType t; - private Configuration config0; - - TaintStoreNode() { this = TTaintStoreNode(arg, t, config0) } - - override Node getNode() { none() } - - override DataFlowType getErasedNodeTypeBound() { result = t } - - override DataFlowCallable getEnclosingCallable() { result = arg.getEnclosingCallable() } - - override predicate isCand1(Configuration config) { config = config0 } - - override string toString() { result = arg.toString() + " [taint store]" } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - arg.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } -} - -private predicate additionalLocalFlowStepExt( - NodeExt node1, NodeExt node2, DataFlowType t, Configuration config -) { - exists(ArgumentNode arg, Content f | - node1 = TReadTaintNode(arg, f, config) and - argumentFlowsThrough(arg, node2.getNode(), _, t, TSummaryReadTaint(f), config) - ) - or - node2 = TTaintStoreNode(node1.getNode(), t, config) -} - -pragma[nomagic] -private predicate readExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - read(node1.getNode(), f, node2.getNode(), config) - or - node2 = TReadStoreNode(_, node1.getNode(), f, config) - or - node2 = TReadTaintNode(node1.getNode(), f, config) -} - -pragma[nomagic] -private predicate storeExt(NodeExt node1, Content f, NodeExt node2, Configuration config) { - store(node1.getNode(), f, node2.getNode(), config) - or - exists(DataFlowCall call, ArgumentNode arg, Content f1, Node n2 | - node1 = TReadStoreNode(call, arg, f1, config) and - n2 = node2.getNode() and - argumentValueFlowsThrough(call, arg, TContentSome(f1), TContentSome(f), n2) and +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - readStoreCand1(f, unbind(config)) - ) - or - exists(ArgumentNode arg, DataFlowType t | - node1 = TTaintStoreNode(arg, t, config) and - argumentFlowsThrough(arg, node2.getNode(), t, _, TSummaryTaintStore(f), config) + store(n1, tc, n2, _) and + c = tc.getContent() ) } -private predicate jumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - jumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate additionalJumpStepExt(NodeExt node1, NodeExt node2, Configuration config) { - additionalJumpStep(node1.getNode(), node2.getNode(), config) -} - -private predicate argumentValueFlowsThrough(NodeExt node1, NodeExt node2) { - argumentValueFlowsThrough(_, node1.getNode(), TContentNone(), TContentNone(), node2.getNode()) -} - -private predicate argumentFlowsThrough( - NodeExt arg, NodeExt out, DataFlowType t, Configuration config -) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable. - */ -pragma[noinline] -private predicate localFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - localFlowStep(n1, n2, config) - or - nodeCand1(n1, config) and - argumentValueFlowsThrough(_, n1, TContentNone(), TContentNone(), n2) - ) -} - -/** - * Holds if data can flow from `node1` to `node2` in one local step or a step - * through a callable, in both cases using an additional flow step from the - * configuration. - */ -pragma[noinline] -private predicate additionalLocalFlowStepOrFlowThroughCallable( - NodeExt node1, NodeExt node2, Configuration config -) { - exists(Node n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() - | - nodeCand1(n1, config) and - additionalLocalFlowStep(n1, n2, config) - or - argumentFlowsThrough(n1, n2, _, _, TSummaryTaint(), config) - ) - or - additionalLocalFlowStepExt(node1, node2, _, config) +pragma[nomagic] +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + read(n1, c, n2) } pragma[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, config) +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. */ -private predicate flowOutOfCallableNodeCand1(ReturnNodeExt node1, Node node2, Configuration config) { - nodeCand1(node2, config) and - not outBarrier(node1, config) and - not inBarrier(node2, config) and - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition1(node1, unbind(config)) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. */ -private predicate flowIntoCallableNodeCand1( - ArgumentNode node1, ParameterNode node2, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config ) { - viableParamArgCand(_, node2, node1, config) + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) } /** @@ -999,7 +649,7 @@ private predicate flowIntoCallableNodeCand1( private int branch(Node n1, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n1, n, conf) or flowIntoCallableNodeCand1(n1, n, conf) + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) ) } @@ -1011,269 +661,391 @@ private int branch(Node n1, Configuration conf) { private int join(Node n2, Configuration conf) { result = strictcount(Node n | - flowOutOfCallableNodeCand1(n, n2, conf) or flowIntoCallableNodeCand1(n, n2, conf) + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) ) } /** - * Holds if data can flow out of a callable from `node1` to `node2`, either + * Holds if data can flow out of `call` from `ret` to `out`, either * through a `ReturnNode` or through an argument that has been mutated, and * that this step is part of a path from a source to a sink. The * `allowsFieldFlow` flag indicates whether the branching is within the limit * specified by the configuration. */ -private predicate flowOutOfCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config ) { - exists(ReturnNodeExt n1, Node n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowOutOfCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if data can flow into a callable and that this step is part of a + * Holds if data can flow into `call` and that this step is part of a * path from a source to a sink. The `allowsFieldFlow` flag indicates whether * the branching is within the limit specified by the configuration. */ -private predicate flowIntoCallableNodeCand1( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config ) { - exists(ArgumentNode n1, ParameterNode n2 | - n1 = node1.getNode() and - n2 = node2.getNode() and - flowIntoCallableNodeCand1(n1, n2, config) and - exists(int b, int j | - b = branch(n1, config) and - j = join(n2, config) and - if b.minimum(j) <= config.fieldFlowBranchLimit() - then allowsFieldFlow = true - else allowsFieldFlow = false - ) + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. */ -private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Configuration config) { - nodeCand1(node.getNode(), config) and - config.isSource(node.getNode()) and +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and fromArg = false and + argStored = TBooleanNone() and stored = false or - node.isCand1(unbind(config)) and + nodeCand1(node, unbind(config)) and ( - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - localFlowStepOrFlowThroughCallable(mid, node, config) + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) ) or - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, stored, config) and - additionalLocalFlowStepOrFlowThroughCallable(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and stored = false ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - jumpStepExt(mid, node, config) and - fromArg = false + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() ) or - exists(NodeExt mid | - nodeCandFwd2(mid, _, stored, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and fromArg = false and + argStored = TBooleanNone() and stored = false ) or // store - exists(NodeExt mid, Content f | - nodeCandFwd2(mid, fromArg, _, config) and - storeExt(mid, f, node, config) and + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, _, stored, config) and - flowIntoCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = true and - (stored = false or allowsFieldFlow = true) - ) + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() or - exists(NodeExt mid, boolean allowsFieldFlow | - nodeCandFwd2(mid, false, stored, config) and - flowOutOfCallableNodeCand1(mid, node, allowsFieldFlow, config) and - fromArg = false and - (stored = false or allowsFieldFlow = true) + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) ) ) } /** - * 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 storeCandFwd2(Content f, boolean stored, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - node.isCand1(unbind(config)) and - nodeCandFwd2(mid, _, stored, config) and - storeExt(mid, f, node, config) + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + storeCand1(mid, c, node, config) ) } pragma[nomagic] -private predicate nodeCandFwd2Read(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid | - nodeCandFwd2(mid, fromArg, true, config) and - readExt(mid, f, node, config) +private predicate nodeCandFwd2Read( + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, c, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) ) } /** - * Holds if `node` is part of a path from a source to a sink in the given - * configuration taking simple call contexts into consideration. + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. */ -private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Configuration config) { - nodeCandFwd2(node, _, false, config) and - config.isSink(node.getNode()) and +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and toReturn = false and + returnRead = TBooleanNone() and read = false or - nodeCandFwd2(node, _, unbindBool(read), unbind(config)) and + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and ( - exists(NodeExt mid | - localFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) ) or - exists(NodeExt mid | - additionalLocalFlowStepOrFlowThroughCallable(node, mid, config) and - nodeCand2(mid, toReturn, read, config) and + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and read = false ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() ) or - exists(NodeExt mid | - additionalJumpStepExt(node, mid, config) and - nodeCand2(mid, _, read, config) and + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and toReturn = false and + returnRead = TBooleanNone() and read = false ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, read, config) and - readCand2(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(NodeExt mid, Content f, boolean read0 | - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read0), unbind(config)) and - nodeCand2(mid, toReturn, read0, 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 ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, false, read, config) and - toReturn = false and - (read = false or allowsFieldFlow = true) + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand1(node, mid, allowsFieldFlow, config) and - nodeCand2(mid, _, read, config) and - toReturn = true and - (read = false or allowsFieldFlow = true) - ) + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() ) } /** - * 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 readCand2(Content f, boolean read, Configuration config) { - exists(NodeExt mid, NodeExt node | +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { + exists(Node mid, Node node | useFieldFlow(config) and - nodeCandFwd2(node, _, true, unbind(config)) and - readExt(node, f, mid, config) and - storeCandFwd2(f, unbindBool(read), unbind(config)) and - nodeCand2(mid, _, read, config) + nodeCandFwd2(node, _, _, true, 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, NodeExt node, boolean toReturn, boolean stored, Configuration config + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config ) { - exists(NodeExt mid | - storeExt(node, f, mid, config) and - nodeCand2(mid, toReturn, true, config) and - nodeCandFwd2(node, _, stored, unbind(config)) - ) -} - -pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) + exists(Node mid | + 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 both a store and a read in the path graph - * covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ -pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { - exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) +pragma[nomagic] +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(c, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +/** + * 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 c, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) + ) +} pragma[nomagic] -private predicate flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } pragma[nomagic] -private predicate flowIntoCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config ) { - flowIntoCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and nodeCand2(node2, config) and nodeCand2(node1, unbind(config)) } @@ -1284,15 +1056,15 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowEntry(Node node, Configuration config) { - nodeCand2(TNormalNode(node), config) and + nodeCand2(node, config) and ( config.isSource(node) or jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or - readDirect(_, _, node) or + node instanceof OutNodeExt or + store(_, _, node, _) or + read(_, _, node) or node instanceof CastNode ) } @@ -1302,15 +1074,13 @@ private module LocalFlowBigStep { * flow steps in a dataflow path. */ private predicate localFlowExit(Node node, Configuration config) { - exists(Node next | nodeCand2(TNormalNode(next), config) | + exists(Node next | nodeCand2(next, config) | jumpStep(node, next, config) or additionalJumpStep(node, next, config) or - flowIntoCallableNodeCand1(node, next, config) or - flowOutOfCallableNodeCand1(node, next, config) or - argumentFlowsThrough(node, next, _, _, _, config) or - argumentValueFlowsThrough(_, node, TContentNone(), TContentNone(), next) or - storeDirect(node, _, next) or - readDirect(node, _, next) + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next, _) or + read(node, _, next) ) or node instanceof CastNode @@ -1318,6 +1088,13 @@ private module LocalFlowBigStep { config.isSink(node) } + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + /** * Holds if the local path from `node1` to `node2` is a prefix of a maximal * subsequence of local flow steps in a dataflow path. @@ -1334,33 +1111,33 @@ private module LocalFlowBigStep { ( localFlowEntry(node1, config) and ( - localFlowStep(node1, node2, config) and + localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and t = getErasedNodeTypeBound(node1) or - additionalLocalFlowStep(node1, node2, config) and + additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and t = getErasedNodeTypeBound(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) or exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and - localFlowStep(mid, node2, config) and + localFlowStepNodeCand1(mid, node2, config) and not mid instanceof CastNode and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and - additionalLocalFlowStep(mid, node2, config) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof CastNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and - nodeCand2(TNormalNode(node2), unbind(config)) + nodeCand2(node2, unbind(config)) ) ) } @@ -1371,311 +1148,380 @@ private module LocalFlowBigStep { */ pragma[nomagic] predicate localFlowBigStep( - Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, LocalCallContext callContext ) { - localFlowStepPlus(node1, node2, preservesValue, t, config, callContext) and + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and localFlowExit(node2, config) } - - pragma[nomagic] - predicate localFlowBigStepExt( - NodeExt node1, NodeExt node2, boolean preservesValue, AccessPathFrontNil apf, - Configuration config - ) { - localFlowBigStep(node1.getNode(), node2.getNode(), preservesValue, apf.getType(), config, _) - or - additionalLocalFlowStepExt(node1, node2, apf.getType(), config) and - nodeCand2(node1, config) and - nodeCand2(node2, unbind(config)) and - preservesValue = false - } } private import LocalFlowBigStep pragma[nomagic] -private predicate readExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - readExt(node1, f, node2, config) and - nodeCand2(node1, _, true, unbind(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 - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeExtCand2(NodeExt node1, Content f, NodeExt node2, Configuration config) { - storeExt(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 - readStoreCand(f, unbind(config)) -} - -private newtype TAccessPathFront = - TFrontNil(DataFlowType t) or - TFrontHead(Content f) - -/** - * The front of an `AccessPath`. This is either a head or a nil. - */ -abstract private class AccessPathFront extends TAccessPathFront { - abstract string toString(); - - abstract DataFlowType getType(); - - abstract boolean toBoolNonEmpty(); - - predicate headUsesContent(Content f) { this = TFrontHead(f) } -} - -private class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } - - override DataFlowType getType() { this = TFrontNil(result) } - - override boolean toBoolNonEmpty() { result = false } -} - -private class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } - - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } - - override boolean toBoolNonEmpty() { result = true } + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** - * Holds if data can flow from a source to `node` with the given `apf`. + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. */ pragma[nomagic] private predicate flowCandFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd0(node, fromArg, apf, config) and - if node instanceof CastingNodeExt - then compatibleTypes(node.getErasedNodeTypeBound(), apf.getType()) + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() } pragma[nomagic] private predicate flowCandFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, Configuration config + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config ) { - nodeCand2(node, _, false, config) and - config.isSource(node.getNode()) and + nodeCand2(node, _, _, false, config) and + config.isSource(node) and fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, fromArg, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) ) or - nodeCand2(node, unbind(config)) and - ( - exists(NodeExt mid | - flowCandFwd(mid, _, apf, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(mid, _, nil, config) and - additionalJumpStepExt(mid, node, config) and - fromArg = false and - apf = TFrontNil(node.getErasedNodeTypeBound()) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, _, apf, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowCandFwd(mid, false, apf, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowCandFwd(mid, fromArg, apf, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil, DataFlowType t | - flowCandFwd(mid, fromArg, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - apf = TFrontNil(t) - ) + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, Content f | - flowCandFwd(mid, fromArg, _, config) and - storeExtCand2(mid, f, node, config) and - nodeCand2(node, _, true, unbind(config)) and - apf.headUsesContent(f) + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) ) or - exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + // store + 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(tc) and + compatibleTypes(apf0.getType(), contentType) + ) + or + // read + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) ) } pragma[nomagic] -private predicate consCandFwd(Content f, AccessPathFront apf, Configuration config) { - exists(NodeExt mid, NodeExt n | - flowCandFwd(mid, _, apf, config) and - storeExtCand2(mid, f, n, config) and - nodeCand2(n, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, tc, n, contentType, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead(Content f, NodeExt node, boolean fromArg, Configuration config) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, apf0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config +) { + 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] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) ) } /** - * Holds if data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. */ pragma[nomagic] -private predicate flowCand(NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config) { - flowCand0(node, toReturn, apf, config) and - flowCandFwd(node, _, apf, config) +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) } pragma[nomagic] private predicate flowCand0( - NodeExt node, boolean toReturn, AccessPathFront apf, Configuration config + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config ) { - flowCandFwd(node, _, apf, config) and - config.isSink(node.getNode()) and + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and toReturn = false and + returnApf = TAccessPathFrontNone() and apf instanceof AccessPathFrontNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flowCand(mid, toReturn, apf, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flowCand(mid, toReturn, nil, config) and + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and apf instanceof AccessPathFrontNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flowCand(mid, _, apf, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) + ) + or + // read + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and - toReturn = false and - apf instanceof AccessPathFrontNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, false, apf, config) and - toReturn = false and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flowCand(mid, _, apf, config) and - toReturn = true and - (apf instanceof AccessPathFrontNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flowCand(mid, toReturn, apf, config) - ) - or - exists(NodeExt mid, AccessPathFrontNil nil | - argumentFlowsThrough(node, mid, _, config) and - flowCand(mid, toReturn, nil, config) and - apf instanceof AccessPathFrontNil and - flowCandFwd(node, _, apf, config) - ) - or - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and - apf0.headUsesContent(f) and - consCand(f, apf, config) - ) - or - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and - apf.headUsesContent(f) - ) + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + 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( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { - exists(NodeExt mid | - readExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + readCandFwd(node, tc, apf, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - NodeExt node, Content f, boolean toReturn, AccessPathFrontHead apf0, Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate consCand(Content f, AccessPathFront apf, Configuration config) { - consCandFwd(f, apf, config) and - exists(NodeExt 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] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) ) } private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { consCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - consCand(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 @@ -1684,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1695,7 +1541,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 { @@ -1705,7 +1551,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 } @@ -1713,357 +1559,469 @@ 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 + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} /** - * Holds if data can flow from a source to `node` with the given `ap`. + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. */ private predicate flowFwd( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowFwd0(node, fromArg, apf, ap, config) and - flowCand(node, _, apf, config) + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) } private predicate flowFwd0( - NodeExt node, boolean fromArg, AccessPathFront apf, AccessPath ap, Configuration config + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config ) { - flowCand(node, _, _, config) and - config.isSource(node.getNode()) and + flowCand(node, _, _, _, config) and + config.isSource(node) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() or - flowCand(node, _, _, unbind(config)) and + flowCand(node, _, _, _, unbind(config)) and ( - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - localFlowBigStepExt(mid, node, true, _, config) + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, fromArg, _, nil, config) and - localFlowBigStepExt(mid, node, false, apf, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and apf = ap.(AccessPathNil).getFront() ) or - exists(NodeExt mid | - flowFwd(mid, _, apf, ap, config) and - jumpStepExt(mid, node, config) and - fromArg = false - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(mid, _, _, nil, config) and - additionalJumpStepExt(mid, node, config) and + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and fromArg = false and - ap = TNil(node.getErasedNodeTypeBound()) and - apf = ap.(AccessPathNil).getFront() + argAp = TAccessPathNone() ) or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, _, apf, ap, config) and - flowIntoCallableNodeCand2(mid, node, allowsFieldFlow, config) and - fromArg = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowFwd(mid, false, apf, ap, config) and - flowOutOfCallableNodeCand2(mid, node, allowsFieldFlow, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and fromArg = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - flowFwd(mid, fromArg, apf, ap, config) and - argumentValueFlowsThrough(mid, node) - ) - or - exists(NodeExt mid, AccessPathNil nil, DataFlowType t | - flowFwd(mid, fromArg, _, nil, config) and - argumentFlowsThrough(mid, node, t, config) and - ap = TNil(t) and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and apf = ap.(AccessPathNil).getFront() ) ) or - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and - ap = push(f, ap0) + // store + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + or + // read + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) ) } pragma[nomagic] private predicate flowFwdStore( - NodeExt node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, - Configuration config + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeExtCand2(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( - NodeExt mid, Content f, NodeExt 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 - consCand(f, apf0, config) and - apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config +) { + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(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 flowConsCandFwd( - Content f, AccessPathFront apf, AccessPath ap, Configuration config +private predicate flowFwdConsCand( + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore0(n, tc, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } /** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, ap, config) and - flowFwd(node, _, _, ap, config) +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) } -private predicate flow0(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flowFwd(node, _, _, ap, config) and - config.isSink(node.getNode()) and +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and toReturn = false and + returnAp = TAccessPathNone() and ap instanceof AccessPathNil or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and ap instanceof AccessPathNil ) or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) ) or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - additionalJumpStepExt(node, mid, config) and - flow(mid, _, nil, config) and - toReturn = false and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowIntoCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, false, ap, config) and - toReturn = false and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid, boolean allowsFieldFlow | - flowOutOfCallableNodeCand2(node, mid, allowsFieldFlow, config) and - flow(mid, _, ap, config) and - toReturn = true and - (ap instanceof AccessPathNil or allowsFieldFlow = true) - ) - or - exists(NodeExt mid | - argumentValueFlowsThrough(node, mid) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - argumentFlowsThrough(node, mid, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil and - flowFwd(node, _, _, ap, config) - ) - or - exists(Content f | - flowStore(f, node, toReturn, ap, config) and - flowConsCand(f, ap, config) - ) - or - exists(NodeExt mid, AccessPath ap0 | - readFwd(node, _, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) - ) + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() } pragma[nomagic] -private predicate storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate storeFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeExtCand2(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, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config ) { - exists(NodeExt mid, AccessPath ap0 | - storeFwd(node, f, mid, ap, ap0, config) and - flow(mid, toReturn, ap0, config) + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, tc, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] -private predicate readFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate readFlowFwd( + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and - ap0 = pop(f, ap) and - flowConsCandFwd(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) { - exists(NodeExt n, NodeExt mid | - flow(mid, _, ap, config) and - readFwd(n, f, mid, _, ap, config) +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, tc, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) ) } bindingset[conf, result] private Configuration unbind(Configuration conf) { result >= conf and result <= conf } -private predicate flow(Node n, Configuration config) { flow(TNormalNode(n), _, _, config) } +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} private newtype TSummaryCtx = TSummaryCtxNone() or TSummaryCtxSome(ParameterNode p, AccessPath ap) { - exists(ReturnNodeExt ret, Configuration config | flow(TNormalNode(p), true, ap, config) | - exists(Summary summary | - parameterFlowReturn(p, ret, _, _, _, summary, config) and - flow(ret, unbind(config)) - | - // taint through - summary = TSummaryTaint() and - ap instanceof AccessPathNil - or - // taint setter - summary = TSummaryTaintStore(_) and - ap instanceof AccessPathNil - or - // taint getter - summary = TSummaryReadTaint(ap.(AccessPathConsNil).getHead()) - ) - or - exists(ContentOption contentIn | - parameterValueFlowReturn(p, ret, _, contentIn, _) and - flow(ret, unbind(config)) - | - // value through/setter - contentIn = TContentNone() - or - // value getter (+ setter) - contentIn = TContentSome(ap.getHead()) - ) + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) ) } @@ -2113,7 +2071,7 @@ private newtype TPathNode = exists(PathNodeMid mid | pathStep(mid, node, cc, sc, ap) and config = mid.getConfiguration() and - flow(TNormalNode(node), _, ap, unbind(config)) + flow(node, _, _, ap, unbind(config)) ) } or TPathNodeSink(Node node, Configuration config) { @@ -2164,14 +2122,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 @@ -2246,7 +2221,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 @@ -2283,7 +2258,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) } } @@ -2293,17 +2268,18 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { * a callable is recorded by `cc`. */ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { - exists( - AccessPath ap0, Node midnode, Configuration conf, DataFlowCallable enclosing, - LocalCallContext localCC - | - pathIntoLocalStep(mid, midnode, cc, enclosing, sc, ap0, conf) and - localCC = getLocalCallContext(cc, enclosing) + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() | localFlowBigStep(midnode, node, true, _, conf, localCC) and ap = ap0 or - localFlowBigStep(midnode, node, false, ap.(AccessPathNil).getType(), conf, localCC) and + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and ap0 instanceof AccessPathNil ) or @@ -2318,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(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() @@ -2332,44 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - -pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and +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) { - storeDirect(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() } @@ -2399,11 +2363,11 @@ private predicate pathOutOfCallable1( } pragma[noinline] -private Node getAnOutNodeCand( +private Node getAnOutNodeFlow( ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config ) { result = kind.getAnOutNode(call) and - flow(TNormalNode(result), _, ap, config) + flow(result, _, _, ap, config) } /** @@ -2415,7 +2379,7 @@ private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | pathOutOfCallable1(mid, call, kind, cc, ap, config) | - out = getAnOutNodeCand(kind, call, ap, config) + out = getAnOutNodeFlow(kind, call, ap, config) ) } @@ -2439,7 +2403,7 @@ private predicate parameterCand( DataFlowCallable callable, int i, AccessPath ap, Configuration config ) { exists(ParameterNode p | - flow(TNormalNode(p), _, ap, config) and + flow(p, _, _, ap, config) and p.isParameterOf(callable, i) ) } @@ -2514,7 +2478,7 @@ pragma[noinline] private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { exists(DataFlowCall call, ReturnKindExt kind | pathThroughCallable0(call, mid, kind, cc, ap) and - out = getAnOutNodeCand(kind, call, ap, mid.getConfiguration()) + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) ) } @@ -2555,10 +2519,7 @@ private module FlowExploration { viableParamArg(_, node2, node1) or // flow out of a callable - exists(DataFlowCall call, ReturnKindExt kind | - getReturnPosition(node1) = viableReturnPos(call, kind) and - node2 = kind.getAnOutNode(call) - ) + viableReturnPosOut(_, getReturnPosition(node1), node2) | c1 = node1.getEnclosingCallable() and c2 = node2.getEnclosingCallable() and @@ -2603,10 +2564,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 @@ -2615,7 +2576,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 @@ -2626,7 +2587,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(); @@ -2644,15 +2605,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)) } } @@ -2828,11 +2789,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(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2851,35 +2813,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 - storeDirect(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 783ac641e6e..1f42c21d5a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -26,13 +26,30 @@ private module Cached { ) } - /** Provides predicates for calculating flow-through summaries. */ + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ private module FlowThrough { /** * The first flow-through approximation: * - * - Input/output access paths are abstracted with a Boolean parameter + * - Input access paths are abstracted with a Boolean parameter * that indicates (non-)emptiness. */ private module Cand { @@ -40,83 +57,47 @@ private module Cached { * Holds if `p` can flow to `node` in the same callable using only * value-preserving steps. * - * `read` indicates whether it is contents of `p` that can flow to `node`, - * and `stored` indicates whether it flows to contents of `node`. + * `read` indicates whether it is contents of `p` that can flow to `node`. */ pragma[nomagic] - private predicate parameterValueFlowCand( - ParameterNode p, Node node, boolean read, boolean stored - ) { + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { p = node and - read = false and - stored = false + read = false or // local flow exists(Node mid | - parameterValueFlowCand(p, mid, read, stored) and + parameterValueFlowCand(p, mid, read) and simpleLocalFlowStep(mid, node) ) or // read - exists(Node mid, boolean readMid, boolean storedMid | - parameterValueFlowCand(p, mid, readMid, storedMid) and - readStep(mid, _, node) and - stored = false - | - // value neither read nor stored prior to read - readMid = false and - storedMid = false and - read = true - or - // value (possibly read and then) stored prior to read (same content) - read = readMid and - storedMid = true - ) - or - // store exists(Node mid | - parameterValueFlowCand(p, mid, read, false) and - storeStep(mid, _, node) and - stored = true + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true ) or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, false, false) and - argumentValueFlowsThroughCand(arg, node, read, stored) + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArgCand(p, arg, read, stored) and - argumentValueFlowsThroughCand(arg, node, false, false) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, boolean mid | - parameterValueFlowArgCand(p, arg, read, mid) and - argumentValueFlowsThroughCand(arg, node, mid, stored) + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) ) } pragma[nomagic] - private predicate parameterValueFlowArgCand( - ParameterNode p, ArgumentNode arg, boolean read, boolean stored - ) { - parameterValueFlowCand(p, arg, read, stored) + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) } pragma[nomagic] predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { - parameterValueFlowCand(p, n.getPreUpdateNode(), false, false) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdateCand( - ParameterNode p, PostUpdateNode n, boolean read - ) { - parameterValueFlowCand(p, n, read, true) + parameterValueFlowCand(p, n.getPreUpdateNode(), false) } /** @@ -125,33 +106,21 @@ private module Cached { * into account. * * `read` indicates whether it is contents of `p` that can flow to the return - * node, and `stored` indicates whether it flows to contents of the return * node. */ - predicate parameterValueFlowReturnCand( - ParameterNode p, ReturnKindExt kind, boolean read, boolean stored - ) { + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { exists(ReturnNode ret | - parameterValueFlowCand(p, ret, read, stored) and - kind = TValueReturn(ret.getKind()) - ) - or - exists(ParameterNode p2, int pos2, PostUpdateNode n | - parameterValueFlowsToPostUpdateCand(p, n, read) and - parameterValueFlowsToPreUpdateCand(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 and - stored = true + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() ) } pragma[nomagic] private predicate argumentValueFlowsThroughCand0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, boolean read, boolean stored + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturnCand(param, kind, read, stored) + parameterValueFlowReturnCand(param, kind, read) ) } @@ -159,22 +128,19 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `read` indicates whether it is contents of `arg` that can flow to `out`, and - * `stored` indicates whether it flows to contents of `out`. + * `read` indicates whether it is contents of `arg` that can flow to `out`. */ - predicate argumentValueFlowsThroughCand( - ArgumentNode arg, Node out, boolean read, boolean stored - ) { - exists(DataFlowCall call, ReturnKindExt kind | - argumentValueFlowsThroughCand0(call, arg, kind, read, stored) and - out = kind.getAnOutNode(call) + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) ) } predicate cand(ParameterNode p, Node n) { - parameterValueFlowCand(p, n, _, _) and + parameterValueFlowCand(p, n, _) and ( - parameterValueFlowReturnCand(p, _, _, _) + parameterValueFlowReturnCand(p, _, _) or parameterValueFlowsToPreUpdateCand(p, _) ) @@ -187,7 +153,6 @@ private module Cached { ( n instanceof ParameterNode or n instanceof OutNode or - n instanceof PostUpdateNode or readStep(_, _, n) or n instanceof CastNode ) @@ -200,10 +165,6 @@ private module Cached { or n instanceof ReturnNode or - Cand::parameterValueFlowsToPreUpdateCand(_, n) - or - storeStep(n, _, _) - or readStep(n, _, _) or n instanceof CastNode @@ -237,230 +198,167 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output 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. */ - cached 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), and `contentOut` describes the content of `node` that - * it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) 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 - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) - or - // (getter+)setter - exists(Content fOut | - contentOut.getContent() = fOut and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f, ContentOption contentInMid, ContentOption contentOutMid | - parameterValueFlow(p, mid, contentInMid, contentOutMid) and - readStep(mid, f, node) - | - // value neither read nor stored prior to read - contentInMid = TContentNone() and - contentOutMid = TContentNone() and - contentIn.getContent() = f and - contentOut = TContentNone() and - Cand::parameterValueFlowReturnCand(p, _, true, _) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) - or - // value (possibly read and then) stored prior to read (same content) - contentIn = contentInMid and - contentOutMid.getContent() = f and - contentOut = TContentNone() + 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), read.getContainerType()) ) or - // store - exists(Node mid, Content f | - parameterValueFlow(p, mid, contentIn, TContentNone()) and - storeStep(mid, f, node) and - contentOut.getContent() = f - | - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), f.getType()) - or - compatibleTypes(contentIn.getContent().getType(), f.getType()) - ) - or - // flow through: no prior read or store + // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone(), TContentNone()) and - argumentValueFlowsThrough(_, arg, contentIn, contentOut, node) + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or - // flow through: no read or store inside method + // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, contentOut) and - argumentValueFlowsThrough(_, arg, TContentNone(), TContentNone(), node) - ) - or - // flow through: possible prior read and prior store with compatible - // flow-through method - exists(ArgumentNode arg, ContentOption contentMid | - parameterValueFlowArg(p, arg, contentIn, contentMid) and - argumentValueFlowsThrough(_, arg, contentMid, contentOut, node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, read) and + Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through `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), and - * `contentOut` describes the content of `out` that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate argumentValueFlowsThrough( - DataFlowCall call, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut, - Node out - ) { - exists(ReturnKindExt kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, contentOut) and - out = kind.getAnOutNode(call) + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and - contentOut = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - contentOut = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) - or - // setter - exists(Content fOut | - contentIn = TContentNone() and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fOut.getType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) - or - // getter+setter - exists(Content fIn, Content fOut | - contentIn.getContent() = fIn and - contentOut.getContent() = fOut and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fOut.getContainerType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } /** - * 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. + * 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. */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() + 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), and `contentOut` describes the content of the return - * node that it flows to (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { - ret = - any(ReturnNode n | - parameterValueFlow(p, n, contentIn, contentOut) and - kind = TValueReturn(n.getKind()) - ) - or - ret = - any(PostUpdateNode n | - exists(ParameterNode p2, int pos2 | - parameterValueFlowsToPostUpdate(p, n, contentIn, contentOut) and - parameterValueFlowsToPreUpdate(p2, n) and - p2.isParameterOf(_, pos2) and - kind = TParamUpdate(pos2) and - p != p2 - ) - ) + exists(ReturnNode ret | + parameterValueFlow(p, ret, read) and + kind = ret.getKind() + ) } } import Final } + /** + * 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(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and + containerType = getErasedNodeTypeBound(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 = getErasedNodeTypeBound(n1) and + containerType = getErasedNodeTypeBound(n2) + ) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,17 +367,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate storeDirect(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), TContentNone(), 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 @@ -520,6 +409,24 @@ private module Cached { newtype TReturnKindExt = TValueReturn(ReturnKind kind) or TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + 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(TypedContent tc) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,26 +436,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 = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) +} -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()" } } /** @@ -678,6 +597,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 @@ -688,7 +619,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 { @@ -700,7 +631,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 { @@ -712,9 +645,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()) ) } @@ -779,77 +712,79 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -newtype TSummary = - TSummaryVal() or - TSummaryTaint() or - TSummaryReadVal(Content f) or - TSummaryReadTaint(Content f) or - TSummaryTaintStore(Content f) - -/** - * A summary of flow through a callable. This can either be value-preserving - * if no additional steps are used, taint-flow if at least one additional step - * is used, or any one of those combined with a store or a read. Summaries - * recorded at a return node are restricted to include at least one additional - * step, as the value-based summaries are calculated independent of the - * configuration. - */ -class Summary extends TSummary { - string toString() { - result = "Val" and this = TSummaryVal() - or - result = "Taint" and this = TSummaryTaint() - or - exists(Content f | - result = "ReadVal " + f.toString() and this = TSummaryReadVal(f) - or - result = "ReadTaint " + f.toString() and this = TSummaryReadTaint(f) - or - result = "TaintStore " + f.toString() and this = TSummaryTaintStore(f) - ) - } - - /** Gets the summary that results from extending this with an additional step. */ - Summary additionalStep() { - this = TSummaryVal() and result = TSummaryTaint() - or - this = TSummaryTaint() and result = TSummaryTaint() - or - exists(Content f | this = TSummaryReadVal(f) and result = TSummaryReadTaint(f)) - or - exists(Content f | this = TSummaryReadTaint(f) and result = TSummaryReadTaint(f)) - } - - /** Gets the summary that results from extending this with a read. */ - Summary readStep(Content f) { this = TSummaryVal() and result = TSummaryReadVal(f) } - - /** Gets the summary that results from extending this with a store. */ - Summary storeStep(Content f) { this = TSummaryTaint() and result = TSummaryTaintStore(f) } - - /** Gets the summary that results from extending this with `step`. */ - bindingset[this, step] - Summary compose(Summary step) { - this = TSummaryVal() and result = step - or - this = TSummaryTaint() and - (step = TSummaryTaint() or step = TSummaryTaintStore(_)) and - result = step - or - exists(Content f | - this = TSummaryReadVal(f) and step = TSummaryTaint() and result = TSummaryReadTaint(f) - ) - or - this = TSummaryReadTaint(_) and step = TSummaryTaint() and result = this - } - - /** Holds if this summary does not include any taint steps. */ - predicate isPartial() { - this = TSummaryVal() or - this = TSummaryReadVal(_) - } -} - pragma[noinline] DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } -predicate readDirect = readStep/3; +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** 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. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + private DataFlowType t; + + 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 { + private TypedContent tc; + + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} 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..324b026ca2e 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() } } /** @@ -338,3 +311,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..0abf432e1ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -397,9 +397,7 @@ 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() } 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..bc7b4355862 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -296,6 +296,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { ( 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 +322,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 +339,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 @@ -395,7 +401,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 +440,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 +511,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 +589,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..0f0607662e9 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 @@ -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..0f0607662e9 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 @@ -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 0b2b871e129..28de0cf8eed 100644 --- a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll +++ b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll @@ -1,3 +1,11 @@ +/** + * INTERNAL: This is part of the virtual dispatch computation. + * + * Provides a strengthening of the virtual dispatch relation using a dedicated + * data flow check for lambdas, anonymous classes, and other sufficiently + * private classes where all object instantiations are accounted for. + */ + import java private import VirtualDispatch private import semmle.code.java.dataflow.internal.BaseSSA @@ -194,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/dispatch/VirtualDispatch.qll b/java/ql/src/semmle/code/java/dispatch/VirtualDispatch.qll index e291604ab06..bb6884ced06 100644 --- a/java/ql/src/semmle/code/java/dispatch/VirtualDispatch.qll +++ b/java/ql/src/semmle/code/java/dispatch/VirtualDispatch.qll @@ -1,3 +1,8 @@ +/** + * Provides predicates for reasoning about runtime call targets through virtual + * dispatch. + */ + import java import semmle.code.java.dataflow.TypeFlow private import DispatchFlow as DispatchFlow @@ -27,6 +32,7 @@ Callable exactCallable(Call c) { private predicate implCount(MethodAccess m, int c) { strictcount(viableImpl(m)) = c } +/** Gets a viable implementation of the target of the given `Call`. */ Callable viableCallable(Call c) { result = viableImpl(c) or diff --git a/java/ql/src/semmle/code/java/dispatch/WrappedInvocation.qll b/java/ql/src/semmle/code/java/dispatch/WrappedInvocation.qll index 6c57fced300..cbff880ca96 100644 --- a/java/ql/src/semmle/code/java/dispatch/WrappedInvocation.qll +++ b/java/ql/src/semmle/code/java/dispatch/WrappedInvocation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about calls that may invoke one + * of their arguments. + */ + import java import VirtualDispatch diff --git a/java/ql/src/semmle/code/java/frameworks/Assertions.qll b/java/ql/src/semmle/code/java/frameworks/Assertions.qll index 810af5ca41e..3c3d090b993 100644 --- a/java/ql/src/semmle/code/java/frameworks/Assertions.qll +++ b/java/ql/src/semmle/code/java/frameworks/Assertions.qll @@ -7,7 +7,7 @@ import java -newtype AssertKind = +private newtype AssertKind = AssertKindTrue() or AssertKindFalse() or AssertKindNotNull() or @@ -50,6 +50,7 @@ private predicate assertionMethod(Method m, AssertKind kind) { ) } +/** An assertion method. */ class AssertionMethod extends Method { AssertionMethod() { assertionMethod(this, _) } 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/Networking.qll b/java/ql/src/semmle/code/java/frameworks/Networking.qll index 92575995636..70cad9f54ff 100644 --- a/java/ql/src/semmle/code/java/frameworks/Networking.qll +++ b/java/ql/src/semmle/code/java/frameworks/Networking.qll @@ -1,21 +1,25 @@ -/* +/** * Definitions related to `java.net.*`. */ import semmle.code.java.Type +/** The type `java.net.URLConnection`. */ class TypeUrlConnection extends RefType { TypeUrlConnection() { hasQualifiedName("java.net", "URLConnection") } } +/** The type `java.net.Socket`. */ class TypeSocket extends RefType { TypeSocket() { hasQualifiedName("java.net", "Socket") } } +/** The type `java.net.URL`. */ class TypeUrl extends RefType { TypeUrl() { hasQualifiedName("java.net", "URL") } } +/** The method `java.net.URLConnection::getInputStream`. */ class URLConnectionGetInputStreamMethod extends Method { URLConnectionGetInputStreamMethod() { getDeclaringType() instanceof TypeUrlConnection and @@ -24,6 +28,7 @@ class URLConnectionGetInputStreamMethod extends Method { } } +/** The method `java.net.Socket::getInputStream`. */ class SocketGetInputStreamMethod extends Method { SocketGetInputStreamMethod() { getDeclaringType() instanceof TypeSocket and 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/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index c8464e79cf9..c9d2b6e4ddb 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -220,11 +220,16 @@ abstract class JavaSecurityAlgoSpec extends CryptoAlgoSpec { } class JavaSecurityMessageDigest extends JavaSecurityAlgoSpec { JavaSecurityMessageDigest() { exists(Constructor c | c.getAReference() = this | - c.getDeclaringType().getQualifiedName() = "java.security.MessageDigest" + c.getDeclaringType().hasQualifiedName("java.security", "MessageDigest") + ) + or + exists(Method m | m.getAReference() = this | + m.getDeclaringType().hasQualifiedName("java.security", "MessageDigest") and + m.getName() = "getInstance" ) } - override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) } + override Expr getAlgoSpec() { result = this.(Call).getArgument(0) } } class JavaSecuritySignature extends JavaSecurityAlgoSpec { 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/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-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.expected b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected new file mode 100644 index 00000000000..f2874e3694d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected @@ -0,0 +1,7 @@ +| SpringBootActuators.java:6:88:6:120 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:10:5:10:137 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:14:5:14:149 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:18:5:18:101 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:22:5:22:89 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:26:40:26:108 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | +| SpringBootActuators.java:30:5:30:113 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | 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 new file mode 100644 index 00000000000..da59919fbe6 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -0,0 +1,104 @@ +import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +public class SpringBootActuators { + protected void configure(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configure2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); + } + + protected void configure3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); + } + + protected void configure4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); + } + + protected void configure5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); + } + + protected void configure6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); + } + + protected void configure7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()); + } + + 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/SpringBootActuators.qlref b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref new file mode 100644 index 00000000000..ec49ecd718c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-016/SpringBootActuators.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/options b/java/ql/test/experimental/query-tests/security/CWE-016/options new file mode 100644 index 00000000000..aeef8fc5abc --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/options @@ -0,0 +1 @@ +//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..fe6677ccf57 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -0,0 +1,180 @@ +edges +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | +| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | +| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | +| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | +| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | +| JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | +| JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | +| JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | +| JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | +| JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | +nodes +| JndiInjection.java:26:38:26:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:30:16:30:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:31:20:31:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:32:29:32:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:33:16:33:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:34:14:34:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:35:22:35:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:19 | name | semmle.label | name | +| JndiInjection.java:38:20:38:23 | name | semmle.label | name | +| JndiInjection.java:39:29:39:32 | name | semmle.label | name | +| JndiInjection.java:40:16:40:19 | name | semmle.label | name | +| JndiInjection.java:41:14:41:17 | name | semmle.label | name | +| JndiInjection.java:42:22:42:25 | name | semmle.label | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:49:16:49:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:50:20:50:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:51:16:51:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:52:14:52:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:53:22:53:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:16:55:19 | name | semmle.label | name | +| JndiInjection.java:56:20:56:23 | name | semmle.label | name | +| JndiInjection.java:57:16:57:19 | name | semmle.label | name | +| JndiInjection.java:58:14:58:17 | name | semmle.label | name | +| JndiInjection.java:59:22:59:25 | name | semmle.label | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:66:16:66:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:67:20:67:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:69:14:69:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:70:22:70:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:72:16:72:19 | name | semmle.label | name | +| JndiInjection.java:73:20:73:23 | name | semmle.label | name | +| JndiInjection.java:74:16:74:19 | name | semmle.label | name | +| JndiInjection.java:75:14:75:17 | name | semmle.label | name | +| JndiInjection.java:76:22:76:25 | name | semmle.label | name | +| JndiInjection.java:79:42:79:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:82:16:82:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:83:16:83:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:90:16:90:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:91:23:91:29 | nameStr | semmle.label | nameStr | +| JndiInjection.java:92:18:92:21 | name | semmle.label | name | +| JndiInjection.java:93:16:93:19 | name | semmle.label | name | +| JndiInjection.java:94:14:94:17 | name | semmle.label | name | +| JndiInjection.java:95:22:95:25 | name | semmle.label | name | +| JndiInjection.java:96:16:96:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:98:16:98:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:99:16:99:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:100:16:100:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:101:16:101:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:103:25:103:31 | nameStr | semmle.label | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:109:16:109:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:110:16:110:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:113:37:113:63 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | +| JndiInjection.java:118:5:118:13 | connector | semmle.label | connector | +| JndiInjection.java:121:27:121:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:124:35:124:40 | urlStr | semmle.label | urlStr | +| JndiInjection.java:128:27:128:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:131:41:131:46 | urlStr | semmle.label | urlStr | +| JndiInjection.java:135:52:135:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:138:37:138:42 | urlStr | semmle.label | urlStr | +| JndiInjection.java:142:52:142:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:145:51:145:56 | urlStr | semmle.label | urlStr | +| JndiInjection.java:149:52:149:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:152:51:152:56 | urlStr | semmle.label | urlStr | +#select +| JndiInjection.java:30:16:30:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:31:20:31:26 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:32:29:32:35 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:33:16:33:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:34:14:34:20 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:35:22:35:28 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:37:16:37:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:38:20:38:23 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:39:29:39:32 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:40:16:40:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:41:14:41:17 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:42:22:42:25 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:49:16:49:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:50:20:50:26 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:51:16:51:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:52:14:52:20 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:53:22:53:28 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:55:16:55:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:56:20:56:23 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:57:16:57:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:58:14:58:17 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:59:22:59:25 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:66:16:66:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:67:20:67:26 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:69:14:69:20 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:70:22:70:28 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:72:16:72:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:73:20:73:23 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:74:16:74:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:75:14:75:17 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:76:22:76:25 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:82:16:82:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79:69 | nameStr | this user input | +| JndiInjection.java:83:16:83:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79: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:91:23:91:29 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:92:18:92:21 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:93:16:93:19 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:94:14:94:17 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:95:22:95:25 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:96:16:96:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96: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:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:99:16:99:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:100:16:100:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:101:16:101:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:103:25:103:31 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | +| JndiInjection.java:110:16:110:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | +| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | +| JndiInjection.java:118:5:118:13 | connector | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | +| JndiInjection.java:124:35:124:40 | urlStr | JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:121:27:121:53 | urlStr | this user input | +| JndiInjection.java:131:41:131:46 | urlStr | JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:128:27:128:53 | urlStr | this user input | +| JndiInjection.java:138:37:138:42 | urlStr | JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:135:52:135:78 | urlStr | this user input | +| JndiInjection.java:145:51:145:56 | urlStr | JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:142:52:142:78 | urlStr | this user input | +| JndiInjection.java:152:51:152:56 | urlStr | JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:149:52:149: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..a169eb4a3ac --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -0,0 +1,191 @@ +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.web.bind.annotation.RequestParam; + +public class JndiInjection { + 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); + } + + 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); + } + + 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); + } + + public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + JndiTemplate ctx = new JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } + + 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()); + } + + 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); + } + + 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(); + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + 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()); + } + + 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); + } + + 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..b9529aa93ce --- /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 \ 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/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/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java b/java/ql/test/experimental/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/experimental/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/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java new file mode 100644 index 00000000000..951015b637e --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.core; + +public interface ContextMapper { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java new file mode 100644 index 00000000000..682de892a42 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.core; + +public interface DirContextOperations { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java b/java/ql/test/experimental/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/experimental/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/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java b/java/ql/test/experimental/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/experimental/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/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java new file mode 100644 index 00000000000..29bee2191d2 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java @@ -0,0 +1,76 @@ +package org.springframework.ldap.core; + +import org.springframework.beans.factory.InitializingBean; + +import java.util.*; + +import javax.naming.Name; +import javax.naming.directory.SearchControls; + +import org.springframework.ldap.filter.Filter; + +import org.springframework.ldap.query.LdapQuery; + +public class LdapTemplate implements LdapOperations, InitializingBean { + public void authenticate(LdapQuery query, String password) { } + + public boolean authenticate(Name base, String filter, String password) { return true; } + + public List find(Name base, Filter filter, SearchControls searchControls, final Class clazz) { return null; } + + public List find(LdapQuery query, Class clazz) { return null; } + + public T findOne(LdapQuery query, Class clazz) { return null; } + + 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/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java new file mode 100644 index 00000000000..250e6da0237 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface NameClassPairCallbackHandler { } diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java new file mode 100644 index 00000000000..a5cbbd2a674 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.filter; + +public class EqualsFilter implements Filter { + public EqualsFilter(String attribute, String value) { } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java new file mode 100644 index 00000000000..b24091e6de0 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.filter; + +public interface Filter { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java new file mode 100644 index 00000000000..bc43dddc6f8 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java @@ -0,0 +1,7 @@ +package org.springframework.ldap.filter; + +public class HardcodedFilter implements Filter { + public HardcodedFilter(String filter) { } + public StringBuffer encode(StringBuffer buff) { return buff; } + public String toString() { return ""; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java new file mode 100644 index 00000000000..80cf59b6040 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.query; + +public interface ConditionCriteria { + ContainerCriteria is(String value); +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java new file mode 100644 index 00000000000..7a68b9fbab7 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.query; + +public interface ContainerCriteria extends LdapQuery { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java new file mode 100644 index 00000000000..c94bb75c20c --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.query; + +public interface LdapQuery { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java new file mode 100644 index 00000000000..2e6c76ccc55 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java @@ -0,0 +1,14 @@ +package org.springframework.ldap.query; + +import javax.naming.Name; +import org.springframework.ldap.filter.Filter; + +public class LdapQueryBuilder { + public static LdapQueryBuilder query() { return null; } + public LdapQuery filter(String hardcodedFilter) { return null; } + public LdapQuery filter(Filter filter) { return null; } + public LdapQuery filter(String filterFormat, Object... params) { return null; } + public LdapQueryBuilder base(String baseDn) { return this; } + public Name base() { return null; } + public ConditionCriteria where(String attribute) { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java new file mode 100644 index 00000000000..a85d74192b3 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.support; + +public class LdapEncoder { + public static String filterEncode(String value) { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java new file mode 100644 index 00000000000..74333407853 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java @@ -0,0 +1,12 @@ +package org.springframework.ldap.support; + +import javax.naming.ldap.LdapName; + +public class LdapNameBuilder { + public static LdapNameBuilder newInstance() { return null; } + public static LdapNameBuilder newInstance(String name) { return null; } + + public LdapNameBuilder add(String name) { return null; } + public LdapNameBuilder add(String key, Object value) { return null; } + public LdapName build() { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java new file mode 100644 index 00000000000..13fee96e004 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java @@ -0,0 +1,7 @@ +package org.springframework.ldap.support; + +import javax.naming.ldap.LdapName; + +public class LdapUtils { + public static LdapName newLdapName(String distinguishedName) { return null; } +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java new file mode 100644 index 00000000000..692a7ae417d --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java @@ -0,0 +1,3 @@ +package org.springframework.beans.factory; + +public interface BeanFactory {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java new file mode 100644 index 00000000000..5d857ca2df2 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java @@ -0,0 +1,3 @@ +package org.springframework.beans.factory; + +public interface HierarchicalBeanFactory extends BeanFactory {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java new file mode 100644 index 00000000000..40fc853a45b --- /dev/null +++ b/java/ql/test/experimental/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/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java new file mode 100644 index 00000000000..d6fe32875da --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java @@ -0,0 +1,3 @@ +package org.springframework.beans.factory; + +public interface ListableBeanFactory extends BeanFactory {} 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/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java new file mode 100644 index 00000000000..e7dd0fd7673 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -0,0 +1,19 @@ +package org.springframework.boot.actuate.autoconfigure.security.servlet; + +import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher; +import org.springframework.web.context.WebApplicationContext; + +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 {} + + private abstract static class AbstractRequestMatcher + extends ApplicationContextRequestMatcher {} +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java new file mode 100644 index 00000000000..19676a1452a --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java @@ -0,0 +1,5 @@ +package org.springframework.boot.security.servlet; + +import org.springframework.security.web.util.matcher.RequestMatcher; + +public abstract class ApplicationContextRequestMatcher implements RequestMatcher {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java new file mode 100644 index 00000000000..e8b0ed28eda --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java @@ -0,0 +1,9 @@ +package org.springframework.context; + +import org.springframework.beans.factory.HierarchicalBeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.core.env.EnvironmentCapable; +import org.springframework.core.io.support.ResourcePatternResolver; + +public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, + MessageSource, ApplicationEventPublisher, ResourcePatternResolver {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java new file mode 100644 index 00000000000..b4b659ff72e --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java @@ -0,0 +1,6 @@ +package org.springframework.context; + +@FunctionalInterface +public interface ApplicationEventPublisher { + void publishEvent(Object event); +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java new file mode 100644 index 00000000000..1012702926d --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java @@ -0,0 +1,3 @@ +package org.springframework.context; + +public interface MessageSource {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java new file mode 100644 index 00000000000..09490c33fa5 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java @@ -0,0 +1,3 @@ +package org.springframework.core.env; + +public interface EnvironmentCapable {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java new file mode 100644 index 00000000000..0422a77c54c --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java @@ -0,0 +1,3 @@ +package org.springframework.core.io; + +public interface ResourceLoader {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java new file mode 100644 index 00000000000..b23a5c73cde --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java @@ -0,0 +1,5 @@ +package org.springframework.core.io.support; + +import org.springframework.core.io.ResourceLoader; + +public interface ResourcePatternResolver extends ResourceLoader {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java new file mode 100644 index 00000000000..800071a30d4 --- /dev/null +++ b/java/ql/test/experimental/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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java new file mode 100644 index 00000000000..5037bd499a1 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java @@ -0,0 +1,6 @@ +package org.springframework.security.config; + +@FunctionalInterface +public interface Customizer { + void customize(T t); +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java new file mode 100644 index 00000000000..6ef43f44d94 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java @@ -0,0 +1,4 @@ +package org.springframework.security.config.annotation; + +public abstract class AbstractConfiguredSecurityBuilder> + extends AbstractSecurityBuilder {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java new file mode 100644 index 00000000000..c9ee05b5c78 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java @@ -0,0 +1,3 @@ +package org.springframework.security.config.annotation; + +public abstract class AbstractSecurityBuilder implements SecurityBuilder {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java new file mode 100644 index 00000000000..0ec0cfc30cc --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java @@ -0,0 +1,3 @@ +package org.springframework.security.config.annotation; + +public interface SecurityBuilder {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java new file mode 100644 index 00000000000..bde989db998 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java @@ -0,0 +1,3 @@ +package org.springframework.security.config.annotation; + +public interface SecurityConfigurer> {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java new file mode 100644 index 00000000000..f44385219bd --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java @@ -0,0 +1,4 @@ +package org.springframework.security.config.annotation; + +public abstract class SecurityConfigurerAdapter> + implements SecurityConfigurer {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java new file mode 100644 index 00000000000..70c3fb15b8f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java @@ -0,0 +1,13 @@ +package org.springframework.security.config.annotation.web; + +import org.springframework.security.web.util.matcher.RequestMatcher; + +public abstract class AbstractRequestMatcherRegistry { + public C anyRequest() { + return null; + } + + public C requestMatchers(RequestMatcher... requestMatchers) { + return null; + } +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java new file mode 100644 index 00000000000..d69f989a1ed --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java @@ -0,0 +1,7 @@ +package org.springframework.security.config.annotation.web; + +import org.springframework.security.config.annotation.SecurityBuilder; +import org.springframework.security.web.DefaultSecurityFilterChain; + +public interface HttpSecurityBuilder> extends + SecurityBuilder {} 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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java new file mode 100644 index 00000000000..7e4f1dceed4 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -0,0 +1,43 @@ +package org.springframework.security.config.annotation.web.builders; + +import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder; +import org.springframework.security.config.annotation.SecurityBuilder; +import org.springframework.security.config.annotation.web.HttpSecurityBuilder; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; + +public final class HttpSecurity extends AbstractConfiguredSecurityBuilder + implements SecurityBuilder, HttpSecurityBuilder { + + public HttpSecurity requestMatcher(RequestMatcher requestMatcher) { + return this; + } + + public HttpSecurity authorizeRequests( + Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer) + throws Exception { + return this; + } + + public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests() + throws Exception { + return null; + } + + public HttpSecurity requestMatchers(Customizer requestMatcherCustomizer) { + return this; + } + + public RequestMatcherConfigurer requestMatchers() { + return null; + } + + public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer { + } + + public class RequestMatcherConfigurer extends AbstractRequestMatcherRegistry { + } +} 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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java new file mode 100644 index 00000000000..b6e75cafadb --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java @@ -0,0 +1,6 @@ +package org.springframework.security.config.annotation.web.configurers; + +import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; + +public abstract class AbstractConfigAttributeRequestMatcherRegistry extends + AbstractRequestMatcherRegistry {} 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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java new file mode 100644 index 00000000000..7a1b56d5f3f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java @@ -0,0 +1,8 @@ +package org.springframework.security.config.annotation.web.configurers; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.HttpSecurityBuilder; +import org.springframework.security.web.DefaultSecurityFilterChain; + +public abstract class AbstractHttpConfigurer, B extends HttpSecurityBuilder> + extends SecurityConfigurerAdapter {} 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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java new file mode 100644 index 00000000000..c5c56d56709 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java @@ -0,0 +1,10 @@ +package org.springframework.security.config.annotation.web.configurers; + +import org.springframework.security.config.annotation.web.HttpSecurityBuilder; + +abstract class AbstractInterceptUrlConfigurer, H extends HttpSecurityBuilder> + extends AbstractHttpConfigurer { + abstract class AbstractInterceptUrlRegistry, T> + extends AbstractConfigAttributeRequestMatcherRegistry { + } +} 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/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java new file mode 100644 index 00000000000..012997dc502 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java @@ -0,0 +1,16 @@ +package org.springframework.security.config.annotation.web.configurers; + +import org.springframework.security.config.annotation.web.HttpSecurityBuilder; + +public final class ExpressionUrlAuthorizationConfigurer> + extends AbstractInterceptUrlConfigurer, H> { + public class ExpressionInterceptUrlRegistry extends + ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { + } + + public class AuthorizedUrl { + public ExpressionInterceptUrlRegistry permitAll() { + return null; + } + } +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java new file mode 100644 index 00000000000..fbd1ff753e6 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java @@ -0,0 +1,3 @@ +package org.springframework.security.web; + +public final class DefaultSecurityFilterChain implements SecurityFilterChain {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java new file mode 100644 index 00000000000..4ecef359d1a --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java @@ -0,0 +1,3 @@ +package org.springframework.security.web; + +public interface SecurityFilterChain {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java new file mode 100644 index 00000000000..05d7a2552db --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java @@ -0,0 +1,3 @@ +package org.springframework.security.web.util.matcher; + +public interface RequestMatcher {} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java new file mode 100644 index 00000000000..5ae52ad123f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value=ElementType.PARAMETER) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java new file mode 100644 index 00000000000..16b5d13fd6e --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java @@ -0,0 +1,5 @@ +package org.springframework.web.context; + +import org.springframework.context.ApplicationContext; + +public interface WebApplicationContext extends ApplicationContext {} diff --git a/java/ql/test/library-tests/Encryption/Test.java b/java/ql/test/library-tests/Encryption/Test.java index 71717f572a5..e5a1996f28c 100644 --- a/java/ql/test/library-tests/Encryption/Test.java +++ b/java/ql/test/library-tests/Encryption/Test.java @@ -2,22 +2,23 @@ package security.library.encryption; import java.util.Arrays; import java.util.List; +import java.security.MessageDigest; class Test { List badStrings = Arrays.asList( - "DES", + "DES", "des", "des_function", "function_using_des", "EncryptWithDES"); - + List goodStrings = Arrays.asList( "AES", "AES_function", // false negative - can't think of a good way to detect this without // catching things we shouldn't "AESEncryption"); - + List unknownStrings = Arrays.asList( // not a use of RC2 (camelCase is tricky) "GetPrc2", @@ -29,4 +30,12 @@ class Test { "species", // can't detect unknown algorithms "SOMENEWACRONYM"); -} \ No newline at end of file + public static abstract class SomeDigest extends MessageDigest { + public SomeDigest() { + super("some"); + } + } + public void test() throws Exception { + MessageDigest.getInstance("another"); + } +} diff --git a/java/ql/test/library-tests/Encryption/blacklist.expected b/java/ql/test/library-tests/Encryption/blacklist.expected index ac5a4430ac4..1e9728f0fcd 100644 --- a/java/ql/test/library-tests/Encryption/blacklist.expected +++ b/java/ql/test/library-tests/Encryption/blacklist.expected @@ -1,5 +1,5 @@ -| Test.java:8:4:8:8 | "DES" | -| Test.java:9:4:9:8 | "des" | -| Test.java:10:4:10:17 | "des_function" | -| Test.java:11:4:11:23 | "function_using_des" | -| Test.java:12:4:12:19 | "EncryptWithDES" | +| Test.java:9:4:9:8 | "DES" | +| Test.java:10:4:10:8 | "des" | +| Test.java:11:4:11:17 | "des_function" | +| Test.java:12:4:12:23 | "function_using_des" | +| Test.java:13:4:13:19 | "EncryptWithDES" | diff --git a/java/ql/test/library-tests/Encryption/cryptoalgospec.expected b/java/ql/test/library-tests/Encryption/cryptoalgospec.expected new file mode 100644 index 00000000000..f9564b1df25 --- /dev/null +++ b/java/ql/test/library-tests/Encryption/cryptoalgospec.expected @@ -0,0 +1,2 @@ +| Test.java:35:4:35:17 | super(...) | Test.java:35:10:35:15 | "some" | +| Test.java:39:3:39:38 | getInstance(...) | Test.java:39:29:39:37 | "another" | diff --git a/java/ql/test/library-tests/Encryption/cryptoalgospec.ql b/java/ql/test/library-tests/Encryption/cryptoalgospec.ql new file mode 100644 index 00000000000..f53a1f6466c --- /dev/null +++ b/java/ql/test/library-tests/Encryption/cryptoalgospec.ql @@ -0,0 +1,5 @@ +import default +import semmle.code.java.security.Encryption + +from CryptoAlgoSpec s +select s, s.getAlgoSpec() diff --git a/java/ql/test/library-tests/Encryption/whitelist.expected b/java/ql/test/library-tests/Encryption/whitelist.expected index a5ad43aaf44..f1b206d7205 100644 --- a/java/ql/test/library-tests/Encryption/whitelist.expected +++ b/java/ql/test/library-tests/Encryption/whitelist.expected @@ -1,2 +1,2 @@ -| Test.java:15:4:15:8 | "AES" | -| Test.java:16:4:16:17 | "AES_function" | +| Test.java:16:4:16:8 | "AES" | +| Test.java:17:4:17:17 | "AES_function" | 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/gettersetter/A.java b/java/ql/test/library-tests/dataflow/getter/A.java similarity index 100% rename from java/ql/test/library-tests/dataflow/gettersetter/A.java rename to java/ql/test/library-tests/dataflow/getter/A.java diff --git a/java/ql/test/library-tests/dataflow/getter/getter.expected b/java/ql/test/library-tests/dataflow/getter/getter.expected new file mode 100644 index 00000000000..b5af3f91a59 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/getter/getter.expected @@ -0,0 +1,6 @@ +| A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | +| A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | +| A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | +| A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo | +| A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | +| A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/getter/getter.ql b/java/ql/test/library-tests/dataflow/getter/getter.ql new file mode 100644 index 00000000000..02e6920fc7e --- /dev/null +++ b/java/ql/test/library-tests/dataflow/getter/getter.ql @@ -0,0 +1,10 @@ +import java +import semmle.code.java.dataflow.internal.DataFlowImplCommon +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public +import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private + +from Node n1, Content f, Node n2 +where + read(n1, f, n2) or + getterStep(n1, f, n2) +select n1, n2, f diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected deleted file mode 100644 index ba081588706..00000000000 --- a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.expected +++ /dev/null @@ -1,10 +0,0 @@ -| Read | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | -| Read | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | -| Read | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | -| Read | A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo | -| Read | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | -| Read | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | -| Store | A.java:9:16:9:16 | x | A.java:9:5:9:8 | this [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:14:13:14:13 | x | A.java:14:5:14:5 | a [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:20:14:20:14 | 1 | A.java:20:5:20:5 | a [post update] | A.java:2:7:2:9 | foo | -| Store | A.java:22:20:22:20 | 2 | A.java:22:12:22:21 | withFoo(...) | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql b/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql deleted file mode 100644 index ce802982d99..00000000000 --- a/java/ql/test/library-tests/dataflow/gettersetter/gettersetter.ql +++ /dev/null @@ -1,21 +0,0 @@ -import java -import semmle.code.java.dataflow.internal.DataFlowImplCommon -import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public -import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private - -private predicate read(Node n1, Content f, Node n2) { - readDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2) -} - -private predicate store(Node n1, Content f, Node n2) { - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) -} - -from Node n1, Content f, Node n2, string k -where - read(n1, f, n2) and k = "Read" - or - store(n1, f, n2) and k = "Store" -select k, n1, n2, f 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..d9af0f26b34 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java @@ -0,0 +1,33 @@ +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; + + + +class Test { + public static void taintSteps( + 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); + } +} 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..66e1184ce87 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -0,0 +1,6 @@ +| 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(...) | 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..9f750eed6f4 --- /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 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/dataflow/taintsources/SpringMultiPart.java b/java/ql/test/library-tests/dataflow/taintsources/SpringMultiPart.java new file mode 100644 index 00000000000..da5352dcde4 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/taintsources/SpringMultiPart.java @@ -0,0 +1,15 @@ +import org.springframework.web.multipart.MultipartFile; + +public class SpringMultiPart { + MultipartFile file; + + public void test() throws Exception { + file.getBytes(); + file.isEmpty(); + file.getInputStream(); + file.getResource(); + file.getName(); + file.getContentType(); + file.getOriginalFilename(); + } +} diff --git a/java/ql/test/library-tests/dataflow/taintsources/options b/java/ql/test/library-tests/dataflow/taintsources/options index 5273748f49a..4c9e6d3e443 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/options +++ b/java/ql/test/library-tests/dataflow/taintsources/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.2.3 diff --git a/java/ql/test/library-tests/dataflow/taintsources/remote.expected b/java/ql/test/library-tests/dataflow/taintsources/remote.expected index 2787ecb4ee5..bd2b3ac4296 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/remote.expected +++ b/java/ql/test/library-tests/dataflow/taintsources/remote.expected @@ -9,3 +9,9 @@ | RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:20:5:31 | ... + ... | | RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:28:5:31 | path | | RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:6:29:6:35 | command | +| SpringMultiPart.java:7:3:7:17 | getBytes(...) | SpringMultiPart.java:7:3:7:17 | getBytes(...) | +| SpringMultiPart.java:9:3:9:23 | getInputStream(...) | SpringMultiPart.java:9:3:9:23 | getInputStream(...) | +| SpringMultiPart.java:10:3:10:20 | getResource(...) | SpringMultiPart.java:10:3:10:20 | getResource(...) | +| SpringMultiPart.java:11:3:11:16 | getName(...) | SpringMultiPart.java:11:3:11:16 | getName(...) | +| SpringMultiPart.java:12:3:12:23 | getContentType(...) | SpringMultiPart.java:12:3:12:23 | getContentType(...) | +| SpringMultiPart.java:13:3:13:28 | getOriginalFilename(...) | SpringMultiPart.java:13:3:13:28 | getOriginalFilename(...) | 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/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/springframework-5.2.3/LICENSE.txt b/java/ql/test/stubs/springframework-5.2.3/LICENSE.txt new file mode 100644 index 00000000000..ff773796315 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://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 + + https://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/springframework-5.2.3/org/springframework/core/io/InputStreamSource.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/InputStreamSource.java new file mode 100644 index 00000000000..b769895ece7 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/InputStreamSource.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * 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 + * + * https://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.springframework.core.io; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Simple interface for objects that are sources for an {@link InputStream}. + * + *

    This is the base interface for Spring's more extensive {@link Resource} interface. + * + *

    For single-use streams, {@link InputStreamResource} can be used for any + * given {@code InputStream}. Spring's {@link ByteArrayResource} or any + * file-based {@code Resource} implementation can be used as a concrete + * instance, allowing one to read the underlying content stream multiple times. + * This makes this interface useful as an abstract content source for mail + * attachments, for example. + * + * @author Juergen Hoeller + * @since 20.01.2004 + * @see java.io.InputStream + * @see Resource + * @see InputStreamResource + * @see ByteArrayResource + */ +public interface InputStreamSource { + + /** + * Return an {@link InputStream} for the content of an underlying resource. + *

    It is expected that each call creates a fresh stream. + *

    This requirement is particularly important when you consider an API such + * as JavaMail, which needs to be able to read the stream multiple times when + * creating mail attachments. For such a use case, it is required + * that each {@code getInputStream()} call returns a fresh stream. + * @return the input stream for the underlying resource (must not be {@code null}) + * @throws java.io.FileNotFoundException if the underlying resource doesn't exist + * @throws IOException if the content stream could not be opened + */ + InputStream getInputStream() throws IOException; + +} diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/Resource.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/Resource.java new file mode 100644 index 00000000000..1995ee783e6 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/Resource.java @@ -0,0 +1,178 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * 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 + * + * https://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.springframework.core.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; + +import org.springframework.lang.Nullable; + +/** + * Interface for a resource descriptor that abstracts from the actual + * type of underlying resource, such as a file or class path resource. + * + *

    An InputStream can be opened for every resource if it exists in + * physical form, but a URL or File handle can just be returned for + * certain resources. The actual behavior is implementation-specific. + * + * @author Juergen Hoeller + * @since 28.12.2003 + * @see #getInputStream() + * @see #getURL() + * @see #getURI() + * @see #getFile() + * @see WritableResource + * @see ContextResource + * @see UrlResource + * @see FileUrlResource + * @see FileSystemResource + * @see ClassPathResource + * @see ByteArrayResource + * @see InputStreamResource + */ +public interface Resource extends InputStreamSource { + + /** + * Determine whether this resource actually exists in physical form. + *

    This method performs a definitive existence check, whereas the + * existence of a {@code Resource} handle only guarantees a valid + * descriptor handle. + */ + boolean exists(); + + /** + * Indicate whether non-empty contents of this resource can be read via + * {@link #getInputStream()}. + *

    Will be {@code true} for typical resource descriptors that exist + * since it strictly implies {@link #exists()} semantics as of 5.1. + * Note that actual content reading may still fail when attempted. + * However, a value of {@code false} is a definitive indication + * that the resource content cannot be read. + * @see #getInputStream() + * @see #exists() + */ + default boolean isReadable() { + return exists(); + } + + /** + * Indicate whether this resource represents a handle with an open stream. + * If {@code true}, the InputStream cannot be read multiple times, + * and must be read and closed to avoid resource leaks. + *

    Will be {@code false} for typical resource descriptors. + */ + default boolean isOpen() { + return false; + } + + /** + * Determine whether this resource represents a file in a file system. + * A value of {@code true} strongly suggests (but does not guarantee) + * that a {@link #getFile()} call will succeed. + *

    This is conservatively {@code false} by default. + * @since 5.0 + * @see #getFile() + */ + default boolean isFile() { + return false; + } + + /** + * Return a URL handle for this resource. + * @throws IOException if the resource cannot be resolved as URL, + * i.e. if the resource is not available as descriptor + */ + URL getURL() throws IOException; + + /** + * Return a URI handle for this resource. + * @throws IOException if the resource cannot be resolved as URI, + * i.e. if the resource is not available as descriptor + * @since 2.5 + */ + URI getURI() throws IOException; + + /** + * Return a File handle for this resource. + * @throws java.io.FileNotFoundException if the resource cannot be resolved as + * absolute file path, i.e. if the resource is not available in a file system + * @throws IOException in case of general resolution/reading failures + * @see #getInputStream() + */ + File getFile() throws IOException; + + /** + * Return a {@link ReadableByteChannel}. + *

    It is expected that each call creates a fresh channel. + *

    The default implementation returns {@link Channels#newChannel(InputStream)} + * with the result of {@link #getInputStream()}. + * @return the byte channel for the underlying resource (must not be {@code null}) + * @throws java.io.FileNotFoundException if the underlying resource doesn't exist + * @throws IOException if the content channel could not be opened + * @since 5.0 + * @see #getInputStream() + */ + default ReadableByteChannel readableChannel() throws IOException { + return Channels.newChannel(getInputStream()); + } + + /** + * Determine the content length for this resource. + * @throws IOException if the resource cannot be resolved + * (in the file system or as some other known physical resource type) + */ + long contentLength() throws IOException; + + /** + * Determine the last-modified timestamp for this resource. + * @throws IOException if the resource cannot be resolved + * (in the file system or as some other known physical resource type) + */ + long lastModified() throws IOException; + + /** + * Create a resource relative to this resource. + * @param relativePath the relative path (relative to this resource) + * @return the resource handle for the relative resource + * @throws IOException if the relative resource cannot be determined + */ + Resource createRelative(String relativePath) throws IOException; + + /** + * Determine a filename for this resource, i.e. typically the last + * part of the path: for example, "myfile.txt". + *

    Returns {@code null} if this type of resource does not + * have a filename. + */ + @Nullable + String getFilename(); + + /** + * Return a description for this resource, + * to be used for error output when working with the resource. + *

    Implementations are also encouraged to return this value + * from their {@code toString} method. + * @see Object#toString() + */ + String getDescription(); + +} 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/lang/Nullable.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/lang/Nullable.java new file mode 100644 index 00000000000..c9e50668491 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/lang/Nullable.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * 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 + * + * https://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.springframework.lang; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A common Spring annotation to declare that annotated elements can be {@code null} under + * some circumstance. + * + *

    Leverages JSR-305 meta-annotations to indicate nullability in Java to common + * tools with JSR-305 support and used by Kotlin to infer nullability of Spring API. + * + *

    Should be used at parameter, return value, and field level. Methods override should + * repeat parent {@code @Nullable} annotations unless they behave differently. + * + *

    Can be used in association with {@code @NonNullApi} or {@code @NonNullFields} to + * override the default non-nullable semantic to nullable. + * + * @author Sebastien Deleuze + * @author Juergen Hoeller + * @since 5.0 + * @see NonNullApi + * @see NonNullFields + * @see NonNull + */ +@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Nullable { +} diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/util/MultiValueMap.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/util/MultiValueMap.java new file mode 100644 index 00000000000..2429f556502 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/util/MultiValueMap.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2019 the original author or authors. + * + * 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 + * + * https://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.springframework.util; + +import java.util.List; +import java.util.Map; + +import org.springframework.lang.Nullable; + +/** + * Extension of the {@code Map} interface that stores multiple values. + * + * @author Arjen Poutsma + * @since 3.0 + * @param the key type + * @param the value element type + */ +public interface MultiValueMap extends Map> { + + /** + * Return the first value for the given key. + * @param key the key + * @return the first value for the specified key, or {@code null} if none + */ + @Nullable + V getFirst(K key); + + /** + * Add the given single value to the current list of values for the given key. + * @param key the key + * @param value the value to be added + */ + void add(K key, @Nullable V value); + + /** + * Add all the values of the given list to the current list of values for the given key. + * @param key they key + * @param values the values to be added + * @since 5.0 + */ + void addAll(K key, List values); + + /** + * Add all the values of the given {@code MultiValueMap} to the current values. + * @param values the values to be added + * @since 5.0 + */ + void addAll(MultiValueMap values); + + /** + * {@link #add(Object, Object) Add} the given value, only when the map does not + * {@link #containsKey(Object) contain} the given key. + * @param key the key + * @param value the value to be added + * @since 5.2 + */ + default void addIfAbsent(K key, @Nullable V value) { + if (!containsKey(key)) { + add(key, value); + } + } + + /** + * Set the given single value under the given key. + * @param key the key + * @param value the value to set + */ + void set(K key, @Nullable V value); + + /** + * Set the given values under. + * @param values the values. + */ + void setAll(Map values); + + /** + * Return a {@code Map} with the first values contained in this {@code MultiValueMap}. + * @return a single value representation of this map + */ + Map toSingleValueMap(); + +} diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartFile.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartFile.java new file mode 100644 index 00000000000..1dfb6db2664 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartFile.java @@ -0,0 +1,138 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * 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 + * + * https://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.springframework.web.multipart; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; + +/** + * A representation of an uploaded file received in a multipart request. + * + *

    The file contents are either stored in memory or temporarily on disk. + * In either case, the user is responsible for copying file contents to a + * session-level or persistent store as and if desired. The temporary storage + * will be cleared at the end of request processing. + * + * @author Juergen Hoeller + * @author Trevor D. Cook + * @since 29.09.2003 + * @see org.springframework.web.multipart.MultipartHttpServletRequest + * @see org.springframework.web.multipart.MultipartResolver + */ +public interface MultipartFile extends InputStreamSource { + + /** + * Return the name of the parameter in the multipart form. + * @return the name of the parameter (never {@code null} or empty) + */ + String getName(); + + /** + * Return the original filename in the client's filesystem. + *

    This may contain path information depending on the browser used, + * but it typically will not with any other than Opera. + * @return the original filename, or the empty String if no file has been chosen + * in the multipart form, or {@code null} if not defined or not available + * @see org.apache.commons.fileupload.FileItem#getName() + * @see org.springframework.web.multipart.commons.CommonsMultipartFile#setPreserveFilename + */ + @Nullable + String getOriginalFilename(); + + /** + * Return the content type of the file. + * @return the content type, or {@code null} if not defined + * (or no file has been chosen in the multipart form) + */ + @Nullable + String getContentType(); + + /** + * Return whether the uploaded file is empty, that is, either no file has + * been chosen in the multipart form or the chosen file has no content. + */ + boolean isEmpty(); + + /** + * Return the size of the file in bytes. + * @return the size of the file, or 0 if empty + */ + long getSize(); + + /** + * Return the contents of the file as an array of bytes. + * @return the contents of the file as bytes, or an empty byte array if empty + * @throws IOException in case of access errors (if the temporary store fails) + */ + byte[] getBytes() throws IOException; + + /** + * Return an InputStream to read the contents of the file from. + *

    The user is responsible for closing the returned stream. + * @return the contents of the file as stream, or an empty stream if empty + * @throws IOException in case of access errors (if the temporary store fails) + */ + @Override + InputStream getInputStream() throws IOException; + + /** + * Return a Resource representation of this MultipartFile. This can be used + * as input to the {@code RestTemplate} or the {@code WebClient} to expose + * content length and the filename along with the InputStream. + * @return this MultipartFile adapted to the Resource contract + * @since 5.1 + */ + Resource getResource(); + + /** + * Transfer the received file to the given destination file. + *

    This may either move the file in the filesystem, copy the file in the + * filesystem, or save memory-held contents to the destination file. If the + * destination file already exists, it will be deleted first. + *

    If the target file has been moved in the filesystem, this operation + * cannot be invoked again afterwards. Therefore, call this method just once + * in order to work with any storage mechanism. + *

    NOTE: Depending on the underlying provider, temporary storage + * may be container-dependent, including the base directory for relative + * destinations specified here (e.g. with Servlet 3.0 multipart handling). + * For absolute destinations, the target file may get renamed/moved from its + * temporary location or newly copied, even if a temporary copy already exists. + * @param dest the destination file (typically absolute) + * @throws IOException in case of reading or writing errors + * @throws IllegalStateException if the file has already been moved + * in the filesystem and is not available anymore for another transfer + * @see org.apache.commons.fileupload.FileItem#write(File) + * @see javax.servlet.http.Part#write(String) + */ + void transferTo(File dest) throws IOException, IllegalStateException; + + /** + * Transfer the received file to the given destination file. + *

    The default implementation simply copies the file input stream. + * @since 5.1 + * @see #getInputStream() + * @see #transferTo(File) + */ + void transferTo(Path dest) throws IOException, IllegalStateException; +} diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartRequest.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartRequest.java new file mode 100644 index 00000000000..f5339b47166 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/multipart/MultipartRequest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 + * + * https://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.springframework.web.multipart; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.springframework.lang.Nullable; +import org.springframework.util.MultiValueMap; + +/** + * This interface defines the multipart request access operations that are exposed + * for actual multipart requests. It is extended by {@link MultipartHttpServletRequest}. + * + * @author Juergen Hoeller + * @author Arjen Poutsma + * @since 2.5.2 + */ +public interface MultipartRequest { + + /** + * Return an {@link java.util.Iterator} of String objects containing the + * parameter names of the multipart files contained in this request. These + * are the field names of the form (like with normal parameters), not the + * original file names. + * @return the names of the files + */ + Iterator getFileNames(); + + /** + * Return the contents plus description of an uploaded file in this request, + * or {@code null} if it does not exist. + * @param name a String specifying the parameter name of the multipart file + * @return the uploaded content in the form of a {@link MultipartFile} object + */ + @Nullable + MultipartFile getFile(String name); + + /** + * Return the contents plus description of uploaded files in this request, + * or an empty list if it does not exist. + * @param name a String specifying the parameter name of the multipart file + * @return the uploaded content in the form of a {@link MultipartFile} list + * @since 3.0 + */ + List getFiles(String name); + + /** + * Return a {@link java.util.Map} of the multipart files contained in this request. + * @return a map containing the parameter names as keys, and the + * {@link MultipartFile} objects as values + */ + Map getFileMap(); + + /** + * Return a {@link MultiValueMap} of the multipart files contained in this request. + * @return a map containing the parameter names as keys, and a list of + * {@link MultipartFile} objects as values + * @since 3.0 + */ + MultiValueMap getMultiFileMap(); + + /** + * Determine the content type of the specified request part. + * @param paramOrFileName the name of the part + * @return the associated content type, or {@code null} if not defined + * @since 3.1 + */ + @Nullable + String getMultipartContentType(String paramOrFileName); + +} diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 59ba38b0435..5eb02bc148b 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -19,6 +19,7 @@ + semmlecode-javascript-queries/Security/CWE-094/CodeInjection.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-134/TaintedFormatString.ql: /Security/CWE/CWE-134 + semmlecode-javascript-queries/Security/CWE-201/PostMessageStar.ql: /Security/CWE/CWE-201 diff --git a/javascript/documentation/flow-summaries.rst b/javascript/documentation/flow-summaries.rst index edd6cb027b0..6a6c482f69d 100644 --- a/javascript/documentation/flow-summaries.rst +++ b/javascript/documentation/flow-summaries.rst @@ -5,7 +5,7 @@ Overview -------- This document presents an approach for running information flow analyses (such as the standard -Semmle security queries) on an application that depends on one or more npm packages. Instead of +security queries) on an application that depends on one or more npm packages. Instead of installing the npm packages during the snapshot build and analyzing them together with application code, we analyze each package in isolation and compute *flow summaries* that record information about any sources, sinks and flow steps contributed by the package's API. These flow summaries @@ -41,7 +41,7 @@ If the value of ``p`` can be controlled by an untrusted user, this would allow t folders, which may not be desirable. By analyzing the application code base together with the source code for the ``mkdirp`` package, -Semmle's default path injection analysis would be able to track taint through the call to ``mkdirp`` into its +the default path injection analysis would be able to track taint through the call to ``mkdirp`` into its implementation, which ultimately uses built-in Node.js file system APIs to create the folder. Since the path injection analysis has built-in models of these APIs it would then be able to spot and flag this vulnerability. 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/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..9c31c7afc87 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -77,8 +77,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 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/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 307b656f09a..4a57871c871 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -1588,7 +1588,16 @@ public class TypeScriptASTConverter { } private Node convertLiteralType(JsonObject node, SourceLocation loc) throws ParseError { - return convertChild(node, "literal"); + Node literal = convertChild(node, "literal"); + // Convert a negated literal to a negative number + if (literal instanceof UnaryExpression) { + UnaryExpression unary = (UnaryExpression) literal; + if (unary.getOperator().equals("-") && unary.getArgument() instanceof Literal) { + Literal arg = (Literal) unary.getArgument(); + literal = new Literal(loc, arg.getTokenType(), "-" + arg.getValue()); + } + } + return literal; } private Node convertMappedType(JsonObject node, SourceLocation loc) throws ParseError { diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index d7ead7adecc..0d505ecb578 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -86,6 +86,12 @@ public class TypeScriptParser { */ public static final String TYPESCRIPT_TIMEOUT_VAR = "SEMMLE_TYPESCRIPT_TIMEOUT"; + /** + * An environment variable that can be set to specify a number of retries when verifying + * the TypeScript installation. Default is 3. + */ + public static final String TYPESCRIPT_RETRIES_VAR = "SEMMLE_TYPESCRIPT_RETRIES"; + /** * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be * set to indicate the maximum heap space usable by the Node.js process, in addition to its @@ -179,9 +185,6 @@ public class TypeScriptParser { public String verifyNodeInstallation() { if (nodeJsVersionString != null) return nodeJsVersionString; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - // Determine where to find the Node.js runtime. String explicitNodeJsRuntime = Env.systemEnv().get(TYPESCRIPT_NODE_RUNTIME_VAR); if (explicitNodeJsRuntime != null) { @@ -198,12 +201,41 @@ public class TypeScriptParser { nodeJsRuntimeExtraArgs = Arrays.asList(extraArgs.split("\\s+")); } + // Run 'node --version' with a timeout, and retry a few times if it times out. + // If the Java process is suspended we may get a spurious timeout, and we want to + // support long suspensions in cloud environments. Instead of setting a huge timeout, + // retrying guarantees we can survive arbitrary suspensions as long as they don't happen + // too many times in rapid succession. + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); + int numRetries = Env.systemEnv().getInt(TYPESCRIPT_RETRIES_VAR, 3); + for (int i = 0; i < numRetries - 1; ++i) { + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "We will retry the call that caused this exception."); + System.err.println("Starting Node.js seems to take a long time. Retrying."); + } + } + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "Exception details are not important."); + throw new CatastrophicError( + "Could not start Node.js (timed out after " + (timeout / 1000) + "s and " + numRetries + " attempts"); + } + } + + /** + * Checks that Node.js is installed and can be run and returns its version string. + */ + private String startNodeAndGetVersion(int timeout) throws InterruptedError { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); Builder b = new Builder( getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); @@ -213,10 +245,6 @@ public class TypeScriptParser { "Could not start Node.js. It is required for TypeScript extraction.\n" + stderr); } return nodeJsVersionString = stdout; - } catch (InterruptedError e) { - Exceptions.ignore(e, "Exception details are not important."); - throw new CatastrophicError( - "Could not start Node.js (timed out after " + (timeout / 1000) + "s)."); } catch (ResourceError e) { // In case 'node' is not found, the process builder converts the IOException // into a ResourceError. diff --git a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql index 54ec854bae4..2fb5881723f 100644 --- a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql +++ b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql @@ -3,7 +3,7 @@ * @description An AngularJS event listener that listens for a non-existent event has no effect. * @kind problem * @problem.severity warning - * @precision medium + * @precision low * @id js/angular/dead-event-listener * @tags correctness * frameworks/angularjs diff --git a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql index 8e0baa00fab..b3e0773a157 100644 --- a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql +++ b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql @@ -3,7 +3,7 @@ * @description Unused dependencies are confusing, and should be removed. * @kind problem * @problem.severity recommendation - * @precision high + * @precision low * @id js/angular/unused-dependency * @tags maintainability * frameworks/angularjs diff --git a/javascript/ql/src/DOM/ConflictingAttributes.ql b/javascript/ql/src/DOM/ConflictingAttributes.ql index 58657da9693..1e954164b6f 100644 --- a/javascript/ql/src/DOM/ConflictingAttributes.ql +++ b/javascript/ql/src/DOM/ConflictingAttributes.ql @@ -8,7 +8,7 @@ * @tags maintainability * correctness * external/cwe/cwe-758 - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql b/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql index 2e6b54fc301..fc10f66f533 100644 --- a/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql +++ b/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql @@ -7,7 +7,7 @@ * @tags maintainability * correctness * external/cwe/cwe-563 - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/TooManyParameters.ql b/javascript/ql/src/Declarations/TooManyParameters.ql index 6e17d5373dc..0677c96c5b9 100644 --- a/javascript/ql/src/Declarations/TooManyParameters.ql +++ b/javascript/ql/src/Declarations/TooManyParameters.ql @@ -6,7 +6,7 @@ * @id js/too-many-parameters * @tags testability * readability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql b/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql index 1f131270363..5ef8c0a0f3a 100644 --- a/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql +++ b/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql @@ -108,7 +108,7 @@ predicate signaturesMatch(MethodSignature method, MethodSignature other) { method.getBody().getThisTypeAnnotation().getType() = other.getBody().getThisTypeAnnotation().getType() ) and - // The types are compared in matchingCallSignature. This is sanity-check that the textual representation of the type-annotations are somewhat similar. + // The types are compared in matchingCallSignature. This is a consistency check that the textual representation of the type-annotations are somewhat similar. forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] | getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i) ) and diff --git a/javascript/ql/src/Declarations/UnusedProperty.ql b/javascript/ql/src/Declarations/UnusedProperty.ql index 33896e0a0c1..e9e38409bcb 100644 --- a/javascript/ql/src/Declarations/UnusedProperty.ql +++ b/javascript/ql/src/Declarations/UnusedProperty.ql @@ -5,7 +5,7 @@ * @problem.severity recommendation * @id js/unused-property * @tags maintainability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Expressions/BitwiseSignCheck.ql b/javascript/ql/src/Expressions/BitwiseSignCheck.ql index e28c6db2d91..658960e39af 100644 --- a/javascript/ql/src/Expressions/BitwiseSignCheck.ql +++ b/javascript/ql/src/Expressions/BitwiseSignCheck.ql @@ -6,7 +6,7 @@ * @id js/bitwise-sign-check * @tags reliability * correctness - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Expressions/CompareIdenticalValues.ql b/javascript/ql/src/Expressions/CompareIdenticalValues.ql index 9ad25e5ab10..48eae0c49cd 100644 --- a/javascript/ql/src/Expressions/CompareIdenticalValues.ql +++ b/javascript/ql/src/Expressions/CompareIdenticalValues.ql @@ -11,7 +11,7 @@ * convention * external/cwe/cwe-570 * external/cwe/cwe-571 - * @precision medium + * @precision low */ import Clones diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.qll b/javascript/ql/src/Expressions/ExprHasNoEffect.qll index 86790bb0da3..3818834f529 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.qll +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.qll @@ -158,5 +158,11 @@ predicate hasNoEffect(Expr e) { // exclude block-level flow type annotations. For example: `(name: empty)`. not e.(ParExpr).getExpression().getLastToken().getNextToken().getValue() = ":" and // exclude the first statement of a try block - not e = any(TryStmt stmt).getBody().getStmt(0).(ExprStmt).getExpr() + not e = any(TryStmt stmt).getBody().getStmt(0).(ExprStmt).getExpr() and + // exclude expressions that are alone in a file, and file doesn't contain a function. + not exists(TopLevel top | + top = e.getParent().(ExprStmt).getParent() and + top.getNumChild() = 1 and + not exists(Function fun | fun.getEnclosingContainer() = top) + ) } diff --git a/javascript/ql/src/Expressions/ImplicitOperandConversion.ql b/javascript/ql/src/Expressions/ImplicitOperandConversion.ql index f26654517e5..6b9a308869d 100644 --- a/javascript/ql/src/Expressions/ImplicitOperandConversion.ql +++ b/javascript/ql/src/Expressions/ImplicitOperandConversion.ql @@ -162,7 +162,26 @@ abstract class NullOrUndefinedConversion extends ImplicitConversion { class PlusConversion extends NullOrUndefinedConversion { PlusConversion() { parent instanceof AddExpr or parent instanceof AssignAddExpr } - override string getConversionTarget() { result = "number or string" } + override string getConversionTarget() { + result = getDefiniteSiblingType() + or + not exists(getDefiniteSiblingType()) and + result = "number or string" + } + + /** + * Gets the sibling of this implicit conversion. + * E.g. if this is `a` in the expression `a + b`, then the sibling is `b`. + */ + private Expr getSibling() { result = parent.getAChild() and not result = this.getEnclosingExpr() } + + /** + * Gets the unique type of the sibling expression, if that type is `string` or `number`. + */ + private string getDefiniteSiblingType() { + result = unique(InferredType t | t = getSibling().flow().analyze().getAType()).getTypeofTag() and + result = ["string", "number"] + } } /** diff --git a/javascript/ql/src/Expressions/MisspelledIdentifier.ql b/javascript/ql/src/Expressions/MisspelledIdentifier.ql index 95fd9026149..6eba0ede3a7 100644 --- a/javascript/ql/src/Expressions/MisspelledIdentifier.ql +++ b/javascript/ql/src/Expressions/MisspelledIdentifier.ql @@ -6,7 +6,7 @@ * @id js/misspelled-identifier * @tags maintainability * readability - * @precision high + * @precision low */ import Misspelling diff --git a/javascript/ql/src/Expressions/MisspelledVariableName.ql b/javascript/ql/src/Expressions/MisspelledVariableName.ql index ce5dc546341..b6f0ad88e3e 100644 --- a/javascript/ql/src/Expressions/MisspelledVariableName.ql +++ b/javascript/ql/src/Expressions/MisspelledVariableName.ql @@ -14,6 +14,37 @@ import Misspelling -from GlobalVarAccess gva, VarDecl lvd -where misspelledVariableName(gva, lvd) -select gva, "'" + gva + "' may be a typo for variable $@.", lvd, lvd.getName() +/** + * Gets the number of times a local variable with name `name` occurs in the program. + */ +bindingset[name] +int localAcceses(string name) { + result = count(VarAccess acc | acc.getName() = name and not acc instanceof GlobalVarAccess) +} + +/** + * Gets the number of times a global variable with name `name` occurs in the program. + */ +bindingset[name] +int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) } + +/** + * Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gva`. + * Otherwise the global variable is likely the misspelling. + */ +predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) { + // If there are more occurrences of the global (by a margin of at least 2), and the local is missing one letter compared to the global. + globalAccesses(gva.getName()) >= localAcceses(lvd.getName()) + 2 and + lvd.getName().length() = gva.getName().length() - 1 + or + // Or if there are many more of the global. + globalAccesses(gva.getName()) > 2 * localAcceses(lvd.getName()) + 2 +} + +from GlobalVarAccess gva, VarDecl lvd, string msg +where + misspelledVariableName(gva, lvd) and + if globalIsLikelyCorrect(gva, lvd) + then msg = "$@ may be a typo for '" + gva + "'." + else msg = "'" + gva + "' may be a typo for variable $@." +select gva, msg, lvd, lvd.getName() diff --git a/javascript/ql/src/Expressions/UnknownDirective.ql b/javascript/ql/src/Expressions/UnknownDirective.ql index 4f027db6bbc..c63706d8942 100644 --- a/javascript/ql/src/Expressions/UnknownDirective.ql +++ b/javascript/ql/src/Expressions/UnknownDirective.ql @@ -16,5 +16,7 @@ where // ignore ":" pseudo-directive sometimes seen in dual-use shell/node.js scripts not d.getExpr().getStringValue() = ":" and // but exclude attribute top-levels: `` - not d.getParent() instanceof CodeInAttribute + not d.getParent() instanceof CodeInAttribute and + // exclude babel generated directives like "@babel/helpers - typeof". + not d.getDirectiveText().prefix(14) = "@babel/helpers" select d, "Unknown directive: '" + truncate(d.getDirectiveText(), 20, " ... (truncated)") + "'." diff --git a/javascript/ql/src/JSDoc/BadParamTag.ql b/javascript/ql/src/JSDoc/BadParamTag.ql index b4a9012a0dd..9895f9c608e 100644 --- a/javascript/ql/src/JSDoc/BadParamTag.ql +++ b/javascript/ql/src/JSDoc/BadParamTag.ql @@ -9,7 +9,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql b/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql index 07fa594a28b..8f8190a960f 100644 --- a/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql +++ b/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql @@ -8,7 +8,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/JSDoc/UndocumentedParameter.ql b/javascript/ql/src/JSDoc/UndocumentedParameter.ql index 2a4b64fa82d..f962bc729a1 100644 --- a/javascript/ql/src/JSDoc/UndocumentedParameter.ql +++ b/javascript/ql/src/JSDoc/UndocumentedParameter.ql @@ -8,7 +8,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql b/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql index 426ac694e22..eaa9ffdc1fc 100644 --- a/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql +++ b/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql @@ -7,7 +7,7 @@ * @tags maintainability * readability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp b/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp index 3de37f49759..7690d9df1ce 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp @@ -8,6 +8,11 @@ If the same pattern variable is bound multiple times in the same object or array binding overwrites all of the earlier ones. This is most likely unintended and should be avoided.

    +

    +In TypeScript, a common mistake is to try to write type annotations inside a pattern. This is not +possible, and the type annotation should come after the pattern. +

    + @@ -34,6 +39,21 @@ From context, it appears that the second binding should have been for variable < +

    +This can sometimes happen in TypeScript, due to the apparant similarity between property patterns +and type annotations. In the following example, the function uses a pattern parameter with properties x +and y. These appear to have type number, but are in fact untyped properties both stored in a variable named number. +

    + + + +

    +It is not possible to specify type annotations inside a pattern. The correct way is to specify the type +after the parameter: +

    + + +
  • Mozilla Developer Network: Destructuring assignment.
  • diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql index faa5392806e..5a8bf72dbb2 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql @@ -14,12 +14,55 @@ import javascript -from BindingPattern p, string n, VarDecl v, VarDecl w +class RootDestructuringPattern extends BindingPattern { + RootDestructuringPattern() { + this instanceof DestructuringPattern and + not this = any(PropertyPattern p).getValuePattern() and + not this = any(ArrayPattern p).getAnElement() + } + + /** Holds if this pattern has multiple bindings for `name`. */ + predicate hasConflictingBindings(string name) { + exists(VarRef v, VarRef w | + v = getABindingVarRef() and + w = getABindingVarRef() and + name = v.getName() and + name = w.getName() and + v != w + ) + } + + /** Gets the first occurrence of the conflicting binding `name`. */ + VarDecl getFirstClobberedVarDecl(string name) { + hasConflictingBindings(name) and + result = + min(VarDecl decl | + decl = getABindingVarRef() and decl.getName() = name + | + decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn() + ) + } + + /** Holds if variables in this pattern may resemble type annotations. */ + predicate resemblesTypeAnnotation() { + hasConflictingBindings(_) and // Restrict size of predicate. + this instanceof Parameter and + this instanceof ObjectPattern and + not exists(getTypeAnnotation()) and + getFile().getFileType().isTypeScript() + } +} + +from RootDestructuringPattern p, string n, VarDecl v, VarDecl w, string message where - v = p.getABindingVarRef() and + v = p.getFirstClobberedVarDecl(n) and w = p.getABindingVarRef() and - v.getName() = n and w.getName() = n and v != w and - v.getLocation().startsBefore(w.getLocation()) -select w, "Repeated binding of pattern variable '" + n + "' previously bound $@.", v, "here" + if p.resemblesTypeAnnotation() + then + message = + "The pattern variable '" + n + + "' appears to be a type, but is a variable previously bound $@." + else message = "Repeated binding of pattern variable '" + n + "' previously bound $@." +select w, message, v, "here" diff --git a/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql b/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql index 4f1758d2cd8..83ccabc41ae 100644 --- a/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql +++ b/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql @@ -8,7 +8,7 @@ * @tags reliability * maintainability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql b/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql index a3e73e92167..91e5f58eee6 100644 --- a/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql +++ b/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql @@ -6,7 +6,7 @@ * @id js/json-in-javascript-file * @tags maintainability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts new file mode 100644 index 00000000000..d19e8bb327f --- /dev/null +++ b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts @@ -0,0 +1,3 @@ +function distance({x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} diff --git a/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts new file mode 100644 index 00000000000..ee0f4305507 --- /dev/null +++ b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts @@ -0,0 +1,3 @@ +function distance({x, y}: {x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} diff --git a/javascript/ql/src/NodeJS/CyclicImport.ql b/javascript/ql/src/NodeJS/CyclicImport.ql index 9650c69e4a4..0613b75ccc0 100644 --- a/javascript/ql/src/NodeJS/CyclicImport.ql +++ b/javascript/ql/src/NodeJS/CyclicImport.ql @@ -8,7 +8,7 @@ * @tags reliability * maintainability * frameworks/node.js - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/NodeJS/UnusedDependency.ql b/javascript/ql/src/NodeJS/UnusedDependency.ql index e0b9daca732..92a1d89863b 100644 --- a/javascript/ql/src/NodeJS/UnusedDependency.ql +++ b/javascript/ql/src/NodeJS/UnusedDependency.ql @@ -3,7 +3,7 @@ * @description If unnecessary package dependencies are included in package.json, the * package will become harder to install. * @kind problem - * @problem.severity warning + * @problem.severity recommendation * @id js/node/unused-npm-dependency * @tags maintainability * frameworks/node.js diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 0a9314382f2..617692f3adb 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -27,11 +27,10 @@ class DangerousScheme extends string { /** Returns a node that refers to the scheme of `url`. */ DataFlow::SourceNode schemeOf(DataFlow::Node url) { // url.split(":")[0] - exists(DataFlow::MethodCallNode split | - split.getMethodName() = "split" and - split.getArgument(0).getStringValue() = ":" and - result = split.getAPropertyRead("0") and - url = split.getReceiver() + exists(StringSplitCall split | + split.getSeparator() = ":" and + result = split.getASubstringRead(0) and + url = split.getBaseString() ) or // url.getScheme(), url.getProtocol(), getScheme(url), getProtocol(url) @@ -62,18 +61,14 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) { sw.getSubstring().mayHaveStringValue(scheme) ) or - // check of the form `array.includes(getScheme(nd))` - exists(InclusionTest test, DataFlow::ArrayCreationNode array | test = result | - schemeOf(nd).flowsTo(test.getContainedNode()) and - array.flowsTo(test.getContainerNode()) and - array.getAnElement().mayHaveStringValue(scheme.getWithOrWithoutColon()) - ) - or - // check of the form `getScheme(nd) === scheme` - exists(EqualityTest test, Expr op1, Expr op2 | test.flow() = result | - test.hasOperands(op1, op2) and - schemeOf(nd).flowsToExpr(op1) and - op2.mayHaveStringValue(scheme.getWithOrWithoutColon()) + exists(MembershipCandidate candidate | + result = candidate.getTest() + or + // fall back to the candidate if the test itself is implicit + not exists(candidate.getTest()) and result = candidate + | + candidate.getAMemberString() = scheme.getWithOrWithoutColon() and + schemeOf(nd).flowsTo(candidate) ) or // propagate through trimming, case conversion, and regexp replace diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp new file mode 100644 index 00000000000..5017db6119d --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -0,0 +1,75 @@ + + + +

    + + Dynamically constructing a shell command with inputs from exported + functions may inadvertently change the meaning of the shell command. + + Clients using the exported function may use inputs containing + characters that the shell interprets in a special way, for instance + quotes and spaces. + + This can result in the shell command misbehaving, or even + allowing a malicious user to execute arbitrary commands on the system. +

    + + +
    + + +

    + If possible, provide the dynamic arguments to the shell as an array + using a safe API such as child_process.execFile to avoid + interpretation by the shell. +

    + +

    + Alternatively, if the shell command must be constructed + dynamically, then add code to ensure that special characters + do not alter the shell command unexpectedly. +

    + +
    + + +

    + The following example shows a dynamically constructed shell + command that downloads a file from a remote URL. +

    + + + +

    + The shell command will, however, fail to work as intended if the + input contains spaces or other special characters interpreted in a + special way by the shell. +

    + +

    + Even worse, a client might pass in user-controlled + data, not knowing that the input is interpreted as a shell command. + This could allow a malicious user to provide the input http://example.org; cat /etc/passwd + in order to execute the command cat /etc/passwd. +

    + +

    + To avoid such potentially catastrophic behaviors, provide the + inputs from exported functions as an argument that does not + get interpreted by a shell: +

    + + + +
    + + +
  • + OWASP: + Command Injection. +
  • + +
    +
    diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql new file mode 100644 index 00000000000..4663c1c767c --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql @@ -0,0 +1,23 @@ +/** + * @name Unsafe shell command constructed from library input + * @description Using externally controlled strings in a command line may allow a malicious + * user to change the meaning of the command. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/shell-command-constructed-from-input + * @tags correctness + * security + * external/cwe/cwe-078 + * external/cwe/cwe-088 + */ + +import javascript +import semmle.javascript.security.dataflow.UnsafeShellCommandConstruction::UnsafeShellCommandConstruction +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode +where cfg.hasFlowPath(source, sink) and sinkNode = sink.getNode() +select sinkNode.getAlertLocation(), source, sink, "$@ based on libary input is later used in $@.", + sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), + "shell command" diff --git a/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js new file mode 100644 index 00000000000..d2d1869746f --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js @@ -0,0 +1,5 @@ +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.exec("wget " + path, callback); +} diff --git a/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js new file mode 100644 index 00000000000..9f6bb249adc --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js @@ -0,0 +1,5 @@ +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.execFile("wget", [path], callback); +} diff --git a/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql b/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql index 2df7769906d..e6a74c409f0 100644 --- a/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql +++ b/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql @@ -16,7 +16,8 @@ import semmle.javascript.security.dataflow.UnsafeJQueryPlugin::UnsafeJQueryPlugi import DataFlow::PathGraph from - Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, JQueryPluginMethod plugin + Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, + JQuery::JQueryPluginMethod plugin where cfg.hasFlowPath(source, sink) and source.getNode().(Source).getPlugin() = plugin and diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp new file mode 100644 index 00000000000..5aa2fe63253 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.qhelp @@ -0,0 +1,70 @@ + + + + +

    +Extracting text from a DOM node and interpreting it as HTML can lead to a cross-site scripting vulnerability. +

    +

    +A webpage with this vulnerability reads text from the DOM, and afterwards adds the text as HTML to the DOM. +Using text from the DOM as HTML effectively unescapes the text, and thereby invalidates any escaping done on the text. +If an attacker is able to control the safe sanitized text, then this vulnerability can be exploited to perform a cross-site scripting attack. +

    +
    + + +

    +To guard against cross-site scripting, consider using contextual output encoding/escaping before +writing text to the page, or one of the other solutions that are mentioned in the References section below. +

    +
    + + +

    +The following example shows a webpage using a data-target attribute +to select and manipulate a DOM element using the JQuery library. In the example, the +data-target attribute is read into the target variable, and the +$ function is then supposed to use the target variable as a CSS +selector to determine which element should be manipulated. +

    + +

    +However, if an attacker can control the data-target attribute, +then the value of target can be used to cause the $ function +to execute arbitary JavaScript. +

    +

    +The above vulnerability can be fixed by using $.find instead of $. +The $.find function will only interpret target as a CSS selector +and never as HTML, thereby preventing an XSS attack. +

    + +
    + + +
  • +OWASP: +DOM based +XSS Prevention Cheat Sheet. +
  • +
  • +OWASP: +XSS +(Cross Site Scripting) Prevention Cheat Sheet. +
  • +
  • +OWASP +DOM Based XSS. +
  • +
  • +OWASP +Types of Cross-Site +Scripting. +
  • +
  • +Wikipedia: Cross-site scripting. +
  • +
    +
    diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.ql b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql new file mode 100644 index 00000000000..b4ae70d7e8b --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql @@ -0,0 +1,21 @@ +/** + * @name Cross-site scripting through DOM + * @description Writing user-controlled DOM to HTML can allow for + * a cross-site scripting vulnerability. + * @kind path-problem + * @problem.severity error + * @precision medium + * @id js/xss-through-dom + * @tags security + * external/cwe/cwe-079 + * external/cwe/cwe-116 + */ + +import javascript +import semmle.javascript.security.dataflow.XssThroughDom::XssThroughDom +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", + source.getNode(), "DOM text" diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js new file mode 100644 index 00000000000..97f289516b4 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js @@ -0,0 +1,4 @@ +$("button").click(function () { + var target = $(this).attr("data-target"); + $(target).hide(); +}); diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js new file mode 100644 index 00000000000..a11243cdf23 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js @@ -0,0 +1,4 @@ +$("button").click(function () { + var target = $(this).attr("data-target"); + $.find(target).hide(); +}); diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js index f9bce8ad5d5..113a034219c 100644 --- a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js @@ -1,18 +1,21 @@ -const pg = require('pg'); -const pool = new pg.Pool(config); +const app = require("express")(), + pg = require("pg"), + pool = new pg.Pool(config); -function handler(req, res) { +app.get("search", function handler(req, res) { // BAD: the category might have SQL special characters in it - var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + req.params.category + "' ORDER BY PRICE"; + var query1 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + req.params.category + + "' ORDER BY PRICE"; pool.query(query1, [], function(err, results) { // process results }); // GOOD: use parameters - var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" - + " ORDER BY PRICE"; + var query2 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; pool.query(query2, [req.params.category], function(err, results) { - // process results + // process results }); -} +}); diff --git a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp new file mode 100644 index 00000000000..96d821e30e4 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp @@ -0,0 +1,90 @@ + + + + +

    + + Sanitizing untrusted input for HTML meta-characters is an important + technique for preventing cross-site scripting attacks. Usually, this + is done by escaping <, >, + & and ". However, the context in which + the sanitized value is used decides the characters that + need to be sanitized. + +

    + +

    + + As a consequence, some programs only sanitize + < and > since those are the most + common dangerous characters. The lack of sanitization for + " is problematic when an incompletely sanitized + value is used as an HTML attribute in a string that + later is parsed as HTML. + +

    + +
    + + + +

    + + Sanitize all relevant HTML meta-characters when + constructing HTML dynamically, and pay special attention to where the + sanitized value is used. + +

    + +
    + + + +

    + + The following example code writes part of an HTTP request (which is + controlled by the user) to an HTML attribute of the server response. + + The user-controlled value is, however, not sanitized for + ". This leaves the website vulnerable to cross-site + scripting since an attacker can use a string like " + onclick="alert(42) to inject JavaScript code into the response. + +

    + + + +

    + + Sanitizing the user-controlled data for + " helps prevent the vulnerability: + +

    + + + +
    + + +
  • + OWASP: + DOM based + XSS Prevention Cheat Sheet. +
  • +
  • + OWASP: + XSS + (Cross Site Scripting) Prevention Cheat Sheet. +
  • +
  • + OWASP + Types of Cross-Site. +
  • +
  • + Wikipedia: Cross-site scripting. +
  • +
    + +
    diff --git a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql new file mode 100644 index 00000000000..1788f81bfc2 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql @@ -0,0 +1,41 @@ +/** + * @name Incomplete HTML attribute sanitization + * @description Writing incompletely sanitized values to HTML + * attribute strings can lead to a cross-site + * scripting vulnerability. + * @kind path-problem + * @problem.severity warning + * @precision high + * @id js/incomplete-html-attribute-sanitization + * @tags security + * external/cwe/cwe-079 + * external/cwe/cwe-116 + * external/cwe/cwe-20 + */ + +import javascript +import DataFlow::PathGraph +import semmle.javascript.security.dataflow.IncompleteHtmlAttributeSanitization::IncompleteHtmlAttributeSanitization +import semmle.javascript.security.IncompleteBlacklistSanitizer + +/** + * Gets a pretty string of the dangerous characters for `sink`. + */ +string prettyPrintDangerousCharaters(Sink sink) { + result = + strictconcat(string s | + s = describeCharacters(sink.getADangerousCharacter()) + | + s, ", " order by s + ).regexpReplaceAll(",(?=[^,]+$)", " or") +} + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + // this message is slightly sub-optimal as we do not have an easy way + // to get the flow labels that reach the sink, so the message includes + // all of them in a disjunction + "Cross-site scripting vulnerability as the output of $@ may contain " + + prettyPrintDangerousCharaters(sink.getNode()) + " when it reaches this attribute definition.", + source.getNode(), "this final HTML sanitizer step" diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp new file mode 100644 index 00000000000..e0a070e6669 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -0,0 +1,99 @@ + + + + +

    + + Sanitizing untrusted input for HTML meta-characters is an + important technique for preventing cross-site scripting attacks. But + even a sanitized input can be dangerous to use if it is modified + further before a browser treats it as HTML. + + A seemingly innocent transformation that expands a + self-closing HTML tag from <div attr="{sanitized}"/> + to <div attr="{sanitized}"></div> may + in fact cause cross-site scripting vulnerabilities. + +

    + +
    + + +

    + + Use a well-tested sanitization library if at all + possible, and avoid modifying sanitized values further before treating + them as HTML. + +

    +
    + + + +

    + + The following function transforms a self-closing HTML tag + to a pair of open/close tags. It does so for all non-img + and non-area tags, by using a regular expression with two + capture groups. The first capture group corresponds to the name of the + tag, and the second capture group to the content of the tag. + +

    + + + +

    + + While it is generally known regular expressions are + ill-suited for parsing HTML, variants of this particular transformation + pattern have long been considered safe. + +

    + +

    + + However, the function is not safe. As an example, consider + the following string: + + +

    + + + +

    + + When the above function transforms the string, it becomes + a string that results in an alert when a browser treats it as HTML. + +

    + + + +
    + + +
  • jQuery: + Security fixes in jQuery 3.5.0 +
  • +
  • + OWASP: + DOM based + XSS Prevention Cheat Sheet. +
  • +
  • + OWASP: + XSS + (Cross Site Scripting) Prevention Cheat Sheet. +
  • +
  • + OWASP + Types of Cross-Site. +
  • +
  • + Wikipedia: Cross-site scripting. +
  • +
    + +
    diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql new file mode 100644 index 00000000000..cdb97396a89 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql @@ -0,0 +1,58 @@ +/** + * @name Unsafe expansion of self-closing HTML tag + * @description Using regular expressions to expand self-closing HTML + * tags may lead to cross-site scripting vulnerabilities. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id js/unsafe-html-expansion + * @tags correctness + * security + * external/cwe/cwe-079 + * external/cwe/cwe-116 + */ + +import javascript + +/** + * A regular expression that captures the name and content of a + * self-closing HTML tag such as `
    `. + */ +class SelfClosingTagRecognizer extends DataFlow::RegExpCreationNode { + SelfClosingTagRecognizer() { + exists(RegExpSequence seq, RegExpGroup name, RegExpGroup content | + // `/.../g` + RegExp::isGlobal(this.getFlags()) and + this.getRoot() = seq.getRootTerm() and + // `/<.../` + seq.getChild(0).getConstantValue() = "<" and + // `/...\/>/` + seq.getLastChild().getPredecessor().getConstantValue() = "/" and + seq.getLastChild().getConstantValue() = ">" and + // `/...((...)...).../` + seq.getAChild() = content and + content.getNumber() = 1 and + name.getNumber() = 2 and + name = content.getChild(0).(RegExpSequence).getChild(0) and + // `/...(([a-z]+)...).../` or `/...(([a-z][...]*)...).../` + exists(RegExpQuantifier quant | name.getAChild*() = quant | + quant instanceof RegExpStar or + quant instanceof RegExpPlus + ) and + // `/...((...)[^>]*).../` + exists(RegExpCharacterClass lazy | + name.getSuccessor().(RegExpStar).getChild(0) = lazy and + lazy.isInverted() and + lazy.getAChild().getConstantValue() = ">" + ) + ) + } +} + +from SelfClosingTagRecognizer regexp, StringReplaceCall replace +where + regexp.getAReference().flowsTo(replace.getArgument(0)) and + replace.getRawReplacement().mayHaveStringValue("<$1>") +select replace, + "This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value.", + regexp, "this regular expression" diff --git a/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitization.js b/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitization.js new file mode 100644 index 00000000000..fd0ad78fc47 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitization.js @@ -0,0 +1,9 @@ +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + let id = req.params.id; + id = id.replace(/<|>/g, ""); // BAD + let userHtml = `
    ${getUserName(id) || "Unknown name"}
    `; + // ... + res.send(prefix + userHtml + suffix); +}); diff --git a/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitizationGood.js b/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitizationGood.js new file mode 100644 index 00000000000..54dc96b9f91 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/IncompleteHtmlAttributeSanitizationGood.js @@ -0,0 +1,9 @@ +var app = require('express')(); + +app.get('/user/:id', function(req, res) { + let id = req.params.id; + id = id.replace(/<|>|&|"/g, ""); // GOOD + let userHtml = `
    ${getUserName(id) || "Unknown name"}
    `; + // ... + res.send(prefix + userHtml + suffix); +}); diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html new file mode 100644 index 00000000000..414ac4cea41 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html @@ -0,0 +1,3 @@ +
    diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html new file mode 100644 index 00000000000..1c88927e8ca --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html @@ -0,0 +1,3 @@ +
+<x +"/> diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js new file mode 100644 index 00000000000..598c748bf99 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js @@ -0,0 +1,4 @@ +function expandSelfClosingTags(html) { + var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi; + return html.replace(rxhtmlTag, "<$1>"); // BAD +} diff --git a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js index 06ec12acb9a..2c9eda49426 100644 --- a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js +++ b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js @@ -1 +1,7 @@ -console.log("Unauthorized access attempt by " + user, ip); +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by " + user, ip); +}); diff --git a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js index dcfc6265cf6..4824e55b963 100644 --- a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js +++ b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js @@ -1 +1,7 @@ -console.log("Unauthorized access attempt by %s", user, ip); +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by %s", user, ip); +}); diff --git a/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js b/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js index b2d02d9f6df..1f60b3cd497 100644 --- a/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js +++ b/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js @@ -1,7 +1,9 @@ const crypto = require('crypto'); +var secretText = obj.getSecretText(); + const desCipher = crypto.createCipher('des', key); -let desEncrypted = cipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption +let desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption const aesCipher = crypto.createCipher('aes-128', key); -let aesEncrypted = cipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption +let aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption diff --git a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js index c85f948e2cc..d6fb8443e64 100644 --- a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js +++ b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js @@ -1,11 +1,11 @@ -var express = require('express') -var cookieParser = require('cookie-parser') -var passport = require('passport') +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"); -var app = express() +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); -app.use(cookieParser()) -app.use(passport.authorize({ session: true })) - -app.post('/changeEmail', ..., function (req, res) { -}) +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); diff --git a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js index c3df7b5ad92..5a22b733834 100644 --- a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js +++ b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js @@ -1,13 +1,12 @@ -var express = require('express') -var cookieParser = require('cookie-parser') -var passport = require('passport') -var csrf = require('csurf') +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"), + csrf = require("csurf"); -var app = express() - -app.use(cookieParser()) -app.use(passport.authorize({ session: true })) -app.use(csrf({ cookie:true })) - -app.post('/changeEmail', ..., function (req, res) { -}) +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); +app.use(csrf({ cookie: true })); +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 4198b0f4686..4d3c3eb278f 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -21,11 +21,10 @@ import semmle.javascript.DynamicPropertyAccess * * We restrict this to parameter nodes to focus on "deep assignment" functions. */ -class SplitCall extends MethodCallNode { +class SplitCall extends StringSplitCall { SplitCall() { - getMethodName() = "split" and - getArgument(0).mayHaveStringValue(".") and - getReceiver().getALocalSource() instanceof ParameterNode + getSeparator() = "." and + getBaseString().getALocalSource() instanceof ParameterNode } } @@ -450,8 +449,10 @@ class BlacklistInclusionGuard extends DataFlow::LabeledBarrierGuardNode, Inclusi */ class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode { WhitelistInclusionGuard() { - this instanceof TaintTracking::PositiveIndexOfSanitizer or - this instanceof TaintTracking::InclusionSanitizer + this instanceof TaintTracking::PositiveIndexOfSanitizer + or + this instanceof TaintTracking::MembershipTestSanitizer and + not this = any(MembershipCandidate::ObjectPropertyNameMembershipCandidate c).getTest() // handled with more precision in `HasOwnPropertyGuard` } override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) { diff --git a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js index 477dae218a3..252d4caf923 100644 --- a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js +++ b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js @@ -1,6 +1,7 @@ -const jsyaml = require("js-yaml"); +const app = require("express")(), + jsyaml = require("js-yaml"); -function requestHandler(req, res) { +app.get("load", function(req, res) { let data = jsyaml.load(req.params.data); // ... -} +}); diff --git a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js index f4dd978c07f..fe47631bf2c 100644 --- a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js +++ b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js @@ -1,6 +1,7 @@ -const jsyaml = require("js-yaml"); +const app = require("express")(), + jsyaml = require("js-yaml"); -function requestHandler(req, res) { +app.get("load", function(req, res) { let data = jsyaml.safeLoad(req.params.data); // ... -} +}); diff --git a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js index d062913b26e..0aa4eff9a8f 100644 --- a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js +++ b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js @@ -1,3 +1,5 @@ +const app = require("express")(); + app.get('/some/path', function(req, res) { // BAD: a request parameter is incorporated without validation into a URL redirect res.redirect(req.param("target")); diff --git a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js index 45167b0719f..d2f2a95ef68 100644 --- a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js +++ b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js @@ -1,3 +1,5 @@ +const app = require("express")(); + const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; app.get('/some/path', function(req, res) { diff --git a/javascript/ql/src/Security/CWE-611/examples/Xxe.js b/javascript/ql/src/Security/CWE-611/examples/Xxe.js index 126ab807405..99fa02cc42f 100644 --- a/javascript/ql/src/Security/CWE-611/examples/Xxe.js +++ b/javascript/ql/src/Security/CWE-611/examples/Xxe.js @@ -1,2 +1,7 @@ -const libxml = require('libxmljs'); -var doc = libxml.parseXml(xmlSrc, { noent: true }); +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc, { noent: true }); +}); diff --git a/javascript/ql/src/Security/CWE-611/examples/XxeGood.js b/javascript/ql/src/Security/CWE-611/examples/XxeGood.js index 0abfad1a787..8317dcac98f 100644 --- a/javascript/ql/src/Security/CWE-611/examples/XxeGood.js +++ b/javascript/ql/src/Security/CWE-611/examples/XxeGood.js @@ -1,2 +1,7 @@ -const libxml = require('libxmljs'); -var doc = libxml.parseXml(xmlSrc); +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js b/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js index 85aed596a6b..f72902a5304 100644 --- a/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js +++ b/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js @@ -1,5 +1,10 @@ -const expat = require('node-expat'); -var parser = new expat.Parser(); -parser.on('startElement', handleStart); -parser.on('text', handleText); -parser.write(xmlSrc); +const app = require("express")(), + expat = require("node-expat"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = new expat.Parser(); + parser.on("startElement", handleStart); + parser.on("text", handleText); + parser.write(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js b/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js index 10b6b377a7f..a8c5bc97e63 100644 --- a/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js +++ b/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js @@ -1,5 +1,10 @@ -const sax = require('sax'); -var parser = sax.parser(true); -parser.onopentag = handleStart; -parser.ontext = handleText; -parser.write(xmlSrc); +const app = require("express")(), + sax = require("sax"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = sax.parser(true); + parser.onopentag = handleStart; + parser.ontext = handleText; + parser.write(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js index d19d4518bf0..6d6f9694f1c 100644 --- a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js @@ -1,10 +1,10 @@ -const pg = require('pg') +const pg = require("pg"); const client = new pg.Client({ - user: 'dbuser', - host: 'database.server.com', - database: 'mydb', - password: 'secretpassword', - port: 3211, -}) -client.connect() + user: "bob", + host: "database.server.com", + database: "mydb", + password: "correct-horse-battery-staple", + port: 3211 +}); +client.connect(); diff --git a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js index b8c8518f880..a6d6fb48b1f 100644 --- a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js +++ b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js @@ -1,15 +1,15 @@ -var express = require('express'), - path = require('path'), -var app = express(); +var app = require("express")(), + path = require("path"); -app.get('/user-files', function(req, res) { - var file = req.param('file'); - if (file.indexOf('..') !== -1) { // BAD - // forbid paths outside the /public directory - res.status(400).send('Bad request'); - } else { - var absolute = path.resolve('/public/' + file); - console.log("Sending file: %s", absolute); - res.sendFile(absolute); - } +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } }); diff --git a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js index f9164743794..f2615b1c466 100644 --- a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js +++ b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js @@ -1,15 +1,15 @@ -var express = require('express'), - path = require('path'), -var app = express(); +var app = require("express")(), + path = require("path"); -app.get('/user-files', function(req, res) { - var file = req.param('file'); - if (typeof path !== 'string' || path.indexOf('..') !== -1) { // GOOD - // forbid paths outside the /public directory - res.status(400).send('Bad request'); - } else { - var full = path.resolve('/public/' + file); - console.log("Sending file: %s", full); - res.sendFile(full); - } +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (typeof path !== 'string' || file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } }); diff --git a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js index 73524f6cc91..35a2f2db2cf 100644 --- a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js +++ b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js @@ -1,5 +1,5 @@ +const crypto = require("crypto"); function hashPassword(password) { - var crypto = require("crypto"); var hasher = crypto.createHash('md5'); var hashed = hasher.update(password).digest("hex"); // BAD return hashed; diff --git a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js index 41e3911a88e..592c64a3e18 100644 --- a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js +++ b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js @@ -1,5 +1,5 @@ +const bcrypt = require("bcrypt"); function hashPassword(password, salt) { - var bcrypt = require('bcrypt'); - var hashed = bcrypt.hashSync(password, salt); // GOOD - return hashed; + var hashed = bcrypt.hashSync(password, salt); // GOOD + return hashed; } diff --git a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js index d0eb8b56b0f..1153627dfcc 100644 --- a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js +++ b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js @@ -2,7 +2,7 @@ import http from 'http'; import url from 'url'; var server = http.createServer(function(req, res) { - var target = url.parse(request.url, true).query.target; + var target = url.parse(req.url, true).query.target; // BAD: `target` is controlled by the attacker http.get('https://' + target + ".example.com/data/", res => { diff --git a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js index 2c1662a5a1e..d603ffedc2e 100644 --- a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js +++ b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js @@ -2,7 +2,7 @@ import http from 'http'; import url from 'url'; var server = http.createServer(function(req, res) { - var target = url.parse(request.url, true).query.target; + var target = url.parse(req.url, true).query.target; var subdomain; if (target === 'EU') { diff --git a/javascript/ql/src/Statements/EphemeralLoop.ql b/javascript/ql/src/Statements/EphemeralLoop.ql index e99f0a64ed2..960aee3c074 100644 --- a/javascript/ql/src/Statements/EphemeralLoop.ql +++ b/javascript/ql/src/Statements/EphemeralLoop.ql @@ -6,7 +6,7 @@ * @problem.severity recommendation * @id js/single-run-loop * @tags readability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Statements/NestedLoopsSameVariable.ql b/javascript/ql/src/Statements/NestedLoopsSameVariable.ql index 7288415b903..f3cbb30644f 100644 --- a/javascript/ql/src/Statements/NestedLoopsSameVariable.ql +++ b/javascript/ql/src/Statements/NestedLoopsSameVariable.ql @@ -7,7 +7,7 @@ * @id js/nested-loops-with-same-variable * @tags maintainability * correctness - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Statements/ReturnOutsideFunction.ql b/javascript/ql/src/Statements/ReturnOutsideFunction.ql index 0cbdbe5ac35..ad29920f690 100644 --- a/javascript/ql/src/Statements/ReturnOutsideFunction.ql +++ b/javascript/ql/src/Statements/ReturnOutsideFunction.ql @@ -7,7 +7,7 @@ * @id js/return-outside-function * @tags reliability * correctness - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Statements/UselessConditional.ql b/javascript/ql/src/Statements/UselessConditional.ql index 3f248a3d265..57adc2ed06e 100644 --- a/javascript/ql/src/Statements/UselessConditional.ql +++ b/javascript/ql/src/Statements/UselessConditional.ql @@ -62,6 +62,14 @@ predicate isInitialParameterUse(Expr e) { not p.isRestParameter() ) or + // same as above, but for captured variables + exists(SimpleParameter p, LocalVariable var | + var = p.getVariable() and + var.isCaptured() and + e = var.getAnAccess() and + not p.isRestParameter() + ) + or isInitialParameterUse(e.(LogNotExpr).getOperand()) } diff --git a/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls b/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls index de5f841740c..44e4365689b 100644 --- a/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls +++ b/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-javascript - 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/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls b/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls new file mode 100644 index 00000000000..d20b67f9699 --- /dev/null +++ b/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for JavaScript +- qlpack: codeql-javascript +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/javascript/ql/src/codeql-suites/javascript-security-extended.qls b/javascript/ql/src/codeql-suites/javascript-security-extended.qls new file mode 100644 index 00000000000..734a6335916 --- /dev/null +++ b/javascript/ql/src/codeql-suites/javascript-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for JavaScript +- qlpack: codeql-javascript +- apply: security-extended-selectors.yml + from: codeql-suite-helpers diff --git a/javascript/ql/src/definitions.ql b/javascript/ql/src/definitions.ql index d56fba2e2df..a87857415e6 100644 --- a/javascript/ql/src/definitions.ql +++ b/javascript/ql/src/definitions.ql @@ -6,169 +6,8 @@ * @id js/jump-to-definition */ -import javascript -private import Declarations.Declarations +import definitions -/** - * Gets the kind of reference that `r` represents. - * - * References in callee position have kind `"M"` (for "method"), all - * others have kind `"V"` (for "variable"). - * - * For example, in the expression `f(x)`, `f` has kind `"M"` while - * `x` has kind `"V"`. - */ -string refKind(RefExpr r) { - if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) - then result = "M" - else result = "V" -} - -/** - * Gets a class, function or object literal `va` may refer to. - */ -ASTNode lookupDef(VarAccess va) { - exists(AbstractValue av | av = va.analyze().getAValue() | - result = av.(AbstractClass).getClass() or - result = av.(AbstractFunction).getFunction() or - result = av.(AbstractObjectLiteral).getObjectExpr() - ) -} - -/** - * Holds if `va` is of kind `kind` and `def` is the unique class, - * function or object literal it refers to. - */ -predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { - count(lookupDef(va)) = 1 and - def = lookupDef(va) and - kind = refKind(va) -} - -/** - * Holds if variable access `va` is of kind `kind` and refers to the - * variable declaration. - * - * For example, in the statement `var x = 42, y = x;`, the initializing - * expression of `y` is a variable access `x` of kind `"V"` that refers to - * the declaration `x = 42`. - */ -predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { - // restrict to declarations in same file to avoid accidentally picking up - // unrelated global definitions - decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and - kind = refKind(va) -} - -/** - * Holds if path expression `path`, which appears in a CommonJS `require` - * call or an ES 2015 import statement, imports module `target`; `kind` - * is always "I" (for "import"). - * - * For example, in the statement `var a = require("./a")`, the path expression - * `"./a"` imports a module `a` in the same folder. - */ -predicate importLookup(ASTNode path, Module target, string kind) { - kind = "I" and - ( - exists(Import i | - path = i.getImportedPath() and - target = i.getImportedModule() - ) - or - exists(ReExportDeclaration red | - path = red.getImportedPath() and - target = red.getReExportedModule() - ) - ) -} - -/** - * Gets a node that may write the property read by `prn`. - */ -ASTNode getAWrite(DataFlow::PropRead prn) { - exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName | - base = prn.getBase() and - propName = prn.getPropertyName() and - baseVal = base.getAValue().getAPrototype*() - | - // write to a property on baseVal - exists(AnalyzedPropertyWrite apw | - result = apw.getAstNode() and - apw.writes(baseVal, propName, _) - ) - or - // non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled - // separately - exists(ClassDefinition c, MemberDefinition m | - m = c.getMember(propName) and - baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and - result = m.getNameExpr() - ) - ) -} - -/** - * Holds if `prop` is the property name expression of a property read that - * may read the property written by `write`. Furthermore, `write` must be the - * only such property write. Parameter `kind` is always bound to `"M"` - * at the moment. - */ -predicate propertyLookup(Expr prop, ASTNode write, string kind) { - exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() | - count(getAWrite(prn)) = 1 and - write = getAWrite(prn) and - kind = "M" - ) -} - -/** - * Holds if `ref` is an identifier that refers to a type declared at `decl`. - */ -predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { - exists(TypeAccess typeAccess | - ref = typeAccess.getIdentifier() and - decl = typeAccess.getTypeName().getADefinition() and - kind = "T" - ) -} - -/** - * Holds if `ref` is the callee name of an invocation of `decl`. - */ -predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { - not variableDefLookup(ref, decl, _) and - not propertyLookup(ref, decl, _) and - exists(InvokeExpr invoke, Expr callee | - callee = invoke.getCallee().getUnderlyingReference() and - (ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and - decl = invoke.getResolvedCallee() and - kind = "M" - ) -} - -/** - * Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`. - */ -predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { - decl = ref.getClass().getAstNode() and - kind = "T" -} - -from Locatable ref, ASTNode decl, string kind -where - variableDefLookup(ref, decl, kind) - or - // prefer definitions over declarations - not variableDefLookup(ref, _, _) and variableDeclLookup(ref, decl, kind) - or - importLookup(ref, decl, kind) - or - propertyLookup(ref, decl, kind) - or - typeLookup(ref, decl, kind) - or - typedInvokeLookup(ref, decl, kind) - or - jsdocTypeLookup(ref, decl, kind) -select ref, decl, kind +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) +select e, def, kind diff --git a/javascript/ql/src/definitions.qll b/javascript/ql/src/definitions.qll new file mode 100644 index 00000000000..b6873690a83 --- /dev/null +++ b/javascript/ql/src/definitions.qll @@ -0,0 +1,188 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import javascript +private import Declarations.Declarations + +/** + * Gets the kind of reference that `r` represents. + * + * References in callee position have kind `"M"` (for "method"), all + * others have kind `"V"` (for "variable"). + * + * For example, in the expression `f(x)`, `f` has kind `"M"` while + * `x` has kind `"V"`. + */ +private string refKind(RefExpr r) { + if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) + then result = "M" + else result = "V" +} + +/** + * Gets a class, function or object literal `va` may refer to. + */ +private ASTNode lookupDef(VarAccess va) { + exists(AbstractValue av | av = va.analyze().getAValue() | + result = av.(AbstractClass).getClass() or + result = av.(AbstractFunction).getFunction() or + result = av.(AbstractObjectLiteral).getObjectExpr() + ) +} + +/** + * Holds if `va` is of kind `kind` and `def` is the unique class, + * function or object literal it refers to. + */ +private predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { + count(lookupDef(va)) = 1 and + def = lookupDef(va) and + kind = refKind(va) +} + +/** + * Holds if variable access `va` is of kind `kind` and refers to the + * variable declaration. + * + * For example, in the statement `var x = 42, y = x;`, the initializing + * expression of `y` is a variable access `x` of kind `"V"` that refers to + * the declaration `x = 42`. + */ +private predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { + // restrict to declarations in same file to avoid accidentally picking up + // unrelated global definitions + decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and + kind = refKind(va) +} + +/** + * Holds if path expression `path`, which appears in a CommonJS `require` + * call or an ES 2015 import statement, imports module `target`; `kind` + * is always "I" (for "import"). + * + * For example, in the statement `var a = require("./a")`, the path expression + * `"./a"` imports a module `a` in the same folder. + */ +private predicate importLookup(ASTNode path, Module target, string kind) { + kind = "I" and + ( + exists(Import i | + path = i.getImportedPath() and + target = i.getImportedModule() + ) + or + exists(ReExportDeclaration red | + path = red.getImportedPath() and + target = red.getReExportedModule() + ) + ) +} + +/** + * Gets a node that may write the property read by `prn`. + */ +private ASTNode getAWrite(DataFlow::PropRead prn) { + exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName | + base = prn.getBase() and + propName = prn.getPropertyName() and + baseVal = base.getAValue().getAPrototype*() + | + // write to a property on baseVal + exists(AnalyzedPropertyWrite apw | + result = apw.getAstNode() and + apw.writes(baseVal, propName, _) + ) + or + // non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled + // separately + exists(ClassDefinition c, MemberDefinition m | + m = c.getMember(propName) and + baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and + result = m.getNameExpr() + ) + ) +} + +/** + * Holds if `prop` is the property name expression of a property read that + * may read the property written by `write`. Furthermore, `write` must be the + * only such property write. Parameter `kind` is always bound to `"M"` + * at the moment. + */ +private predicate propertyLookup(Expr prop, ASTNode write, string kind) { + exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() | + count(getAWrite(prn)) = 1 and + write = getAWrite(prn) and + kind = "M" + ) +} + +/** + * Holds if `ref` is an identifier that refers to a type declared at `decl`. + */ +private predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { + exists(TypeAccess typeAccess | + ref = typeAccess.getIdentifier() and + decl = typeAccess.getTypeName().getADefinition() and + kind = "T" + ) +} + +/** + * Holds if `ref` is the callee name of an invocation of `decl`. + */ +private predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { + not variableDefLookup(ref, decl, _) and + not propertyLookup(ref, decl, _) and + exists(InvokeExpr invoke, Expr callee | + callee = invoke.getCallee().getUnderlyingReference() and + (ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and + decl = invoke.getResolvedCallee() and + kind = "M" + ) +} + +/** + * Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`. + */ +private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { + decl = ref.getClass().getAstNode() and + kind = "T" +} + +/** + * 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 imports + */ +cached +ASTNode definitionOf(Locatable e, string kind) { + variableDefLookup(e, result, kind) + or + // prefer definitions over declarations + not variableDefLookup(e, _, _) and variableDeclLookup(e, result, kind) + or + importLookup(e, result, kind) + or + propertyLookup(e, result, kind) + or + typeLookup(e, result, kind) + or + typedInvokeLookup(e, result, kind) + or + jsdocTypeLookup(e, result, kind) +} + +/** + * 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/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp new file mode 100644 index 00000000000..742d2824570 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -0,0 +1,40 @@ + + + + + +

    If you use cross-origin communication between Window objects and do expect to receive messages from other sites, always verify the sender's identity using the origin and possibly source properties of the recevied `MessageEvent`.

    + +

    Unexpected behaviours, like `DOM-based XSS` could occur, if the event handler for incoming data does not check the origin of the data received and handles the data in an unsafe way.

    +
    + + +

    +Always verify the sender's identity of incoming messages. +

    + +
    + + +

    In the first example, the `MessageEvent.data` is passed to the `eval` function withouth checking the origin. This means that any window can send arbitrary messages that will be executed in the window receiving the message

    + + +

    In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be bypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`)

    + + +

    In the third example, the `MessageEvent.origin` is properly checked against a trusted origin.

    + + +
    + + + +
  • CWE-20: Improper Input Validation
  • +
  • Window.postMessage()
  • +
  • Web-message manipulation
  • +
  • The pitfalls of postMessage
  • + +
    +
    diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql new file mode 100644 index 00000000000..2dcfd09c72f --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -0,0 +1,64 @@ +/** + * @name Missing `MessageEvent.origin` verification in `postMessage` handlers + * @description Missing the `MessageEvent.origin` verification in `postMessage` handlers, allows any windows to send arbitrary data to the `MessageEvent` listener. + * This could lead to unexpected behaviour, especially when `MessageEvent.data` is used in an unsafe way. + * @kind problem + * @problem.severity warning + * @precision high + * @id js/missing-postmessageorigin-verification + * @tags correctness + * security + * external/cwe/cwe-20 + */ + +import javascript +import semmle.javascript.security.dataflow.DOM + +/** + * A method call for the insecure functions used to verify the `MessageEvent.origin`. + */ +class InsufficientOriginChecks extends DataFlow::Node { + InsufficientOriginChecks() { + exists(DataFlow::Node node | + this.(StringOps::StartsWith).getSubstring() = node or + this.(StringOps::Includes).getSubstring() = node or + this.(StringOps::EndsWith).getSubstring() = node + ) + } +} + +/** + * A function handler for the `MessageEvent`. + */ +class PostMessageHandler extends DataFlow::FunctionNode { + PostMessageHandler() { this.getFunction() instanceof PostMessageEventHandler } +} + +/** + * The `MessageEvent` parameter received by the handler + */ +class PostMessageEvent extends DataFlow::SourceNode { + PostMessageEvent() { exists(PostMessageHandler handler | this = handler.getParameter(0)) } + + /** + * Holds if an access on `MessageEvent.origin` is in an `EqualityTest` and there is no call of an insufficient verification method on `MessageEvent.origin` + */ + predicate hasOriginChecked() { + exists(EqualityTest test | + this.getAPropertyRead(["origin", "source"]).flowsToExpr(test.getAnOperand()) + ) + } + + /** + * Holds if there is an insufficient method call (i.e indexOf) used to verify `MessageEvent.origin` + */ + predicate hasOriginInsufficientlyChecked() { + exists(InsufficientOriginChecks insufficientChecks | + this.getAPropertyRead("origin").getAMethodCall*() = insufficientChecks + ) + } +} + +from PostMessageEvent event +where not event.hasOriginChecked() or event.hasOriginInsufficientlyChecked() +select event, "Missing or unsafe origin verification." diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js new file mode 100644 index 00000000000..b92887f74e8 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js @@ -0,0 +1,14 @@ +function postMessageHandler(event) { + let origin = event.origin.toLowerCase(); + + let host = window.location.host; + + // BAD + if (origin.indexOf(host) === -1) + return; + + + eval(event.data); +} + +window.addEventListener('message', postMessageHandler, false); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js new file mode 100644 index 00000000000..82c6e4e7dbd --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js @@ -0,0 +1,9 @@ +function postMessageHandler(event) { + let origin = event.origin.toLowerCase(); + + console.log(origin) + // BAD: the origin property is not checked + eval(event.data); +} + +window.addEventListener('message', postMessageHandler, false); diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js new file mode 100644 index 00000000000..e528f980235 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js @@ -0,0 +1,9 @@ +function postMessageHandler(event) { + console.log(event.origin) + // GOOD: the origin property is checked + if (event.origin === 'www.example.com') { + // do something + } +} + +window.addEventListener('message', postMessageHandler, false); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp new file mode 100644 index 00000000000..2b0f08bb81f --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -0,0 +1,56 @@ + + + + +

    +Server-Side Template Injection vulnerabilities occur when user input is embedded +in a template in an unsafe manner allowing attackers to access the template context and +run arbitrary code on the application server. +

    +
    + + +

    +Avoid including user input in any expression or template which may be dynamically rendered. +If user input must be included, use context-specific escaping before including it or run +the rendering engine with sandbox options. +

    +
    + + +

    +The following example shows a page being rendered with user input allowing attackers to access the +template context and run arbitrary code on the application server. +The Pug template engine (and other template engines) provides an interpolation feature - insertion of variable values into a string of some kind. +For example, Hello #{user.username}!, could be used for printing a username from a scoped variable user, +but the user.username expression will be executed as JavaScript. +Unsafe injection of user input in a template therefore allows an attacker to inject arbitrary JavaScript code. +For example, a payload of #{global.process.exit(1)} will cause the below server to crash. +

    + + +
    + + +

    +The example below provides an example of how to use a template engine without any risk of Server-Side Template Injection. +Instead of concatenating user input onto the template, the template uses a placeholder and safely inserts +the user input. +

    + + +
    + + +
  • +OWASP: +Server Side Template Injection. +
  • +
  • +PortSwigger Research Blog: +Server-Side Template Injection. +
  • +
    +
    diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql new file mode 100644 index 00000000000..b4f728b6b15 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -0,0 +1,64 @@ +/** + * @name Server Side Template Injection + * @description Rendering templates with unsanitized user input allows a malicious user arbitrary + * code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/server-side-template-injection + * @tags security + * external/cwe/cwe-094 + */ + +import javascript +import DataFlow +import DataFlow::PathGraph + +class ServerSideTemplateInjectionConfiguration extends TaintTracking::Configuration { + ServerSideTemplateInjectionConfiguration() { this = "ServerSideTemplateInjectionConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ServerSideTemplateInjectionSink } +} + +abstract class ServerSideTemplateInjectionSink extends DataFlow::Node { } + +class SSTIPugSink extends ServerSideTemplateInjectionSink { + SSTIPugSink() { + exists(CallNode compile, ModuleImportNode renderImport | + renderImport = moduleImport(["pug", "jade"]) and + ( + compile = renderImport.getAMemberCall("compile") + or + compile = renderImport.getAMemberCall("render") + ) and + this = compile.getArgument(0) + ) + } +} + +class SSTIDotSink extends ServerSideTemplateInjectionSink { + SSTIDotSink() { + exists(CallNode compile | + compile = moduleImport("dot").getAMemberCall("template") and + this = compile.getArgument(0) + ) + } +} + +class SSTIEjsSink extends ServerSideTemplateInjectionSink { + SSTIEjsSink() { this = moduleImport("ejs").getAMemberCall("render").getArgument(0) } +} + +class SSTINunjucksSink extends ServerSideTemplateInjectionSink { + SSTINunjucksSink() { + this = moduleImport("nunjucks").getAMemberCall("renderString").getArgument(0) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, ServerSideTemplateInjectionConfiguration c +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "$@ flows to here and unsafely used as part of rendered template", source.getNode(), + "User-provided value" diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js new file mode 100644 index 00000000000..c0569ae3929 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js @@ -0,0 +1,35 @@ +const express = require('express') +var bodyParser = require('body-parser'); +const app = express() +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +//Dependent of Templating engine +var jade = require('pug'); +const port = 5061 + +function getHTML(input) { + var template = ` +doctype +html +head + title= 'Hello world' +body + form(action='/' method='post') + label(for='name') Name: + input#name.form-control(type='text', placeholder='' name='name') + button.btn.btn-primary(type='submit') Submit + p Hello `+ input + var fn = jade.compile(template); + var html = fn(); + console.log(html); + return html; +} + +app.post('/', (request, response) => { + var input = request.param('name', "") + var html = getHTML(input) + response.send(html); +}) + +app.listen(port, () => { console.log(`server is listening on ${port}`) }) diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js new file mode 100644 index 00000000000..51407ac7e50 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js @@ -0,0 +1,34 @@ +const express = require('express') +var bodyParser = require('body-parser'); +const app = express() +app.use(bodyParser.urlencoded({ extended: true })); + +//Dependent of Templating engine +var jade = require('pug'); +const port = 5061 + +function getHTML(input) { + var template = ` +doctype +html +head + title= 'Hello world' +body + form(action='/' method='post') + label(for='name') Name: + input#name.form-control(type='text', placeholder='' name='name') + button.btn.btn-primary(type='submit') Submit + p Hello #{username}` + var fn = jade.compile(template); + var html = fn({username: input}); + console.log(html); + return html; +} + +app.post('/', (request, response) => { + var input = request.param('name', "") + var html = getHTML(input) + response.send(html); +}) + +app.listen(port, () => { console.log(`server is listening on ${port}`) }) diff --git a/javascript/ql/src/experimental/poi/PoI.qll b/javascript/ql/src/experimental/poi/PoI.qll new file mode 100644 index 00000000000..20eeeee9f79 --- /dev/null +++ b/javascript/ql/src/experimental/poi/PoI.qll @@ -0,0 +1,325 @@ +/** + * Provides classes and predicates for discovering points of interest + * in an unknown code base. + * + * To use this module, subclass the + * `ActivePoI` class, override *one* of its `is` predicates, and use + * `alertQuery` as a `@kind problem` query . This will present + * the desired points of interest as alerts that are easily browsable + * in a codeql IDE. By itself, this is no different from an ordinary + * query, but the strength of this module lies in its extensibility + * and standard library: + * + * - points of interest can be added, removed and mixed seamlessly + * - this module comes with a collection of standard points of interest (see `StandardPoIs`) + * + * A global configuration for the points of interest (see + * `PoIConfiguration`) can be used to easily manage multiple points of + * interests, and to restrict the points of interest to specific + * corners of the code base. + * + * Below is an example use of this module that will produce an alert + * for each route handler and route handler setup in a file named + * "server-core.js". The route setup alerts will contain a link to its + * associated route handler. + * + * ``` + * /** + * * @kind problem + * *\/ + * + * import PoI + * + * class Configuration extends PoIConfiguration { + * Configuration() { this = "Configuration" } + * + * override predicate shown(DataFlow::Node n) { n.getFile().getBaseName() = "server-core.js" } + * } + * + * class RouteHandlerPoI extends ActivePoI { + * RouteHandlerPoI() { this = "RouteHandlerPoI" } + * override predicate is(DataFlow::Node l0) { l0 instanceof Express::RouteHandler } + * } + * + * class RouteSetupAndRouteHandlerPoI extends ActivePoI { + * RouteSetupAndRouteHandlerPoI() { this = "RouteSetupAndRouteHandlerPoI" } + * + * override predicate is(DataFlow::Node l0, DataFlow::Node l1, string t1) { + * l0.asExpr().(Express::RouteSetup).getARouteHandler() = l1 and t1 = "routehandler" + * } + * } + * + * query predicate problems = alertQuery/6; + * ``` + */ + +import javascript +private import DataFlow +private import filters.ClassifyFiles +private import semmle.javascript.RestrictedLocations + +/** + * Provides often used points of interest. + * + * Note that these points of interest should not extend + * `ActivePoI`, and that they can be enabled on + * demand like this: + * + * ``` + * class MyPoI extends ServerRelatedPoI, ActivePoI {} + * ``` + */ +private module StandardPoIs { + /** + * An unpromoted route setup candidate. + */ + class UnpromotedRouteSetupPoI extends PoI { + UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" } + + override predicate is(Node l0) { + l0 instanceof HTTP::RouteSetupCandidate and not l0.asExpr() instanceof HTTP::RouteSetup + } + } + + /** + * An unpromoted route handler candidate. + */ + class UnpromotedRouteHandlerPoI extends PoI { + UnpromotedRouteHandlerPoI() { this = "UnpromotedRouteHandlerPoI" } + + override predicate is(Node l0) { + l0 instanceof HTTP::RouteHandlerCandidate and not l0 instanceof HTTP::RouteHandler + } + } + + /** + * An unpromoted route handler candidate, with explanatory data flow information. + */ + class UnpromotedRouteHandlerWithFlowPoI extends PoI { + UnpromotedRouteHandlerWithFlowPoI() { this = "UnpromotedRouteHandlerWithFlowPoI" } + + private DataFlow::SourceNode track(HTTP::RouteHandlerCandidate cand, DataFlow::TypeTracker t) { + t.start() and + result = cand + or + exists(DataFlow::TypeTracker t2 | result = track(cand, t2).track(t2, t)) + } + + override predicate is(Node l0, Node l1, string t1) { + l0 instanceof HTTP::RouteHandlerCandidate and + not l0 instanceof HTTP::RouteHandler and + l1 = track(l0, TypeTracker::end()) and + (if l1 = l0 then t1 = "ends here" else t1 = "starts/ends here") + } + } + + /** + * A callee that is unknown. + */ + class UnknownCalleePoI extends PoI { + UnknownCalleePoI() { this = "UnknownCalleePoI" } + + override predicate is(Node l0) { + exists(InvokeNode invk | l0 = invk.getCalleeNode() and not exists(invk.getACallee())) + } + } + + /** + * A source of remote flow. + */ + class RemoteFlowSourcePoI extends PoI { + RemoteFlowSourcePoI() { this = "RemoteFlowSourcePoI" } + + override predicate is(Node l0) { l0 instanceof RemoteFlowSource } + } + + /** + * A "source" for any active configuration. + */ + class SourcePoI extends PoI { + SourcePoI() { this = "SourcePoI" } + + override predicate is(Node l0) { + exists(Configuration cfg | cfg.isSource(l0) or cfg.isSource(l0, _)) + } + } + + /** + * A "sink" for any active configuration. + */ + class SinkPoI extends PoI { + SinkPoI() { this = "SinkPoI" } + + override predicate is(Node l0) { + exists(Configuration cfg | cfg.isSink(l0) or cfg.isSink(l0, _)) + } + } + + /** + * A "barrier" for any active configuration. + */ + class BarrierPoI extends PoI { + BarrierPoI() { this = "BarrierPoI" } + + override predicate is(Node l0) { + exists(Configuration cfg | + cfg.isBarrier(l0) or + cfg.isBarrierEdge(l0, _) or + cfg.isBarrierEdge(l0, _, _) or + cfg.isLabeledBarrier(l0, _) + ) + } + } + + /** + * Provides groups of often used points of interest. + */ + module StandardPoIGroups { + /** + * A server-related point of interest. + */ + class ServerRelatedPoI extends PoI { + ServerRelatedPoI() { + this instanceof UnpromotedRouteSetupPoI or + this instanceof UnpromotedRouteHandlerPoI or + this instanceof UnpromotedRouteHandlerWithFlowPoI + } + } + + /** + * A configuration-related point of interest. + */ + class DataFlowConfigurationPoI extends PoI { + DataFlowConfigurationPoI() { + this instanceof SourcePoI or + this instanceof SinkPoI + } + } + } + + import StandardPoIGroups +} + +import StandardPoIs + +/** + * A tagging interface for a custom point of interest that should be + * enabled in the absence of an explicit + * `PoIConfiguration::enabled/1`. + */ +abstract class ActivePoI extends PoI { + bindingset[this] + ActivePoI() { any() } +} + +private module PoIConfigDefaults { + predicate enabled(PoI poi) { poi instanceof ActivePoI } + + predicate shown(Node n) { not classify(n.getFile(), _) } +} + +/** + * A configuration for the points of interest to display. + */ +abstract class PoIConfiguration extends string { + bindingset[this] + PoIConfiguration() { any() } + + /** + * Holds if the points of interest from `poi` should be shown. + */ + predicate enabled(PoI poi) { PoIConfigDefaults::enabled(poi) } + + /** + * Holds if the points of interest `n` should be shown. + */ + predicate shown(Node n) { PoIConfigDefaults::shown(n) } +} + +/** + * A class of points of interest. + * + * Note that only one of the `is/1`, `is/3`, `is/5` methods should + * be overridden, as two overrides will degrade the alert UI + * slightly. + */ +abstract class PoI extends string { + bindingset[this] + PoI() { any() } + + /** + * Holds if `l0` is a point of interest. + */ + predicate is(Node l0) { none() } + + /** + * Holds if `l0` is a point of interest, with `l1` as an auxiliary location described by `t1`. + */ + predicate is(Node l0, Node l1, string t1) { none() } + + /** + * Holds if `l0` is a point of interest, with `l1` and `l2` as auxiliary locations described by `t1` and `t2`. + */ + predicate is(Node l0, Node l1, string t1, Node l2, string t2) { none() } + + /** + * Gets the message format for the point of interest. + */ + string getFormat() { + is(_) and result = "" + or + is(_, _, _) and result = "$@" + or + is(_, _, _, _, _) and result = "$@ $@" + } +} + +/** + * An alert query for a point of interest. + * + * Should be used as: + * + * ``` + * query predicate problems = alertQuery/6; + * ``` + * + * Or alternatively: + * + * ``` + * from Locatable l1line, string msg, Node l2, string s2, Node l3, string s3 + * where alertQuery(l1line, msg, l2, s2, l3, s3) + * select l1line, msg, l2, s2, l3, s3 + * ``` + * + * Note that some points of interest do not have auxiliary + * locations, so `l2`,`l3`, `s2`, `s3` may have placeholder values. + */ +predicate alertQuery(Locatable l1line, string msg, Node l2, string s2, Node l3, string s3) { + exists(PoI poi, Node l1, string m | + l1.getAstNode().(FirstLineOf) = l1line and + ( + not exists(PoIConfiguration cfg) and + PoIConfigDefaults::enabled(poi) and + PoIConfigDefaults::shown(l1) + or + exists(PoIConfiguration cfg | + cfg.enabled(poi) and + cfg.shown(l1) + ) + ) and + m = poi.getFormat() and + if m = "" then msg = poi else msg = poi + ": " + m + | + poi.is(l1) and + l1 = l2 and + s2 = "irrelevant" and + l1 = l3 and + s3 = "irrelevant" + or + poi.is(l1, l2, s2) and + l1 = l3 and + s3 = "irrelevant" + or + poi.is(l1, l2, s2, l3, s3) + ) +} diff --git a/javascript/ql/src/external/CodeDuplication.qll b/javascript/ql/src/external/CodeDuplication.qll index d0f9d97776a..bd9a0481a8a 100644 --- a/javascript/ql/src/external/CodeDuplication.qll +++ b/javascript/ql/src/external/CodeDuplication.qll @@ -261,6 +261,11 @@ predicate similarContainers(StmtContainer sc, StmtContainer other, float percent ) } +/** + * 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()]) } @@ -275,6 +280,7 @@ private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, Fil ) } +/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ pragma[noopt] private predicate similarLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getNumberOfLines() | @@ -296,6 +302,11 @@ private 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()] @@ -312,6 +323,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ pragma[noopt] private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getNumberOfLines() | @@ -333,6 +345,7 @@ private 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 @@ -343,6 +356,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 diff --git a/javascript/ql/src/filters/ClassifyFiles.ql b/javascript/ql/src/filters/ClassifyFiles.ql index 64606ef685c..fa7aad41ab4 100644 --- a/javascript/ql/src/filters/ClassifyFiles.ql +++ b/javascript/ql/src/filters/ClassifyFiles.ql @@ -7,85 +7,8 @@ * @id js/file-classifier */ -import semmle.javascript.GeneratedCode -import semmle.javascript.frameworks.Testing -import semmle.javascript.frameworks.Templating -import semmle.javascript.dependencies.FrameworkLibraries - -/** - * Holds if `e` may be caused by parsing a template file as plain HTML or JavaScript. - * - * We use two heuristics: check for the presence of a known template delimiter preceding - * the error on the same line, and check whether the file name contains `template` or - * `templates`. - */ -predicate maybeCausedByTemplate(JSParseError e) { - exists(File f | f = e.getFile() | - e.getLine().indexOf(Templating::getADelimiter()) <= e.getLocation().getStartColumn() - or - f.getAbsolutePath().regexpMatch("(?i).*\\btemplates?\\b.*") - ) -} - -/** - * Holds if `e` is an expression in the form `o.p1.p2.p3....pn`. - */ -private predicate isNestedDotExpr(DotExpr e) { - e.getBase() instanceof VarAccess or - isNestedDotExpr(e.getBase()) -} - -/** - * Holds if `tl` only contains variable declarations and field reads. - */ -private predicate looksLikeExterns(TopLevel tl) { - forex(Stmt s | s.getParent() = tl | - exists(VarDeclStmt vds | vds = s | - forall(VariableDeclarator vd | vd = vds.getADecl() | not exists(vd.getInit())) - ) - or - isNestedDotExpr(s.(ExprStmt).getExpr()) - ) -} - -/** - * Holds if `f` is classified as belonging to `category`. - * - * There are currently four categories: - * - `"generated"`: `f` contains generated or minified code; - * - `"test"`: `f` contains test code; - * - `"externs"`: `f` contains externs declarations; - * - `"library"`: `f` contains library code; - * - `"template"`: `f` contains template code. - */ -predicate classify(File f, string category) { - isGenerated(f.getATopLevel()) and category = "generated" - or - ( - exists(Test t | t.getFile() = f) - or - exists(string stemExt | stemExt = "test" or stemExt = "spec" | - f = getTestFile(any(File orig), stemExt) - ) - or - f.getAbsolutePath().regexpMatch(".*/__(mocks|tests)__/.*") - ) and - category = "test" - or - (f.getATopLevel().isExterns() or looksLikeExterns(f.getATopLevel())) and - category = "externs" - or - f.getATopLevel() instanceof FrameworkLibraryInstance and category = "library" - or - exists(JSParseError err | maybeCausedByTemplate(err) | - f = err.getFile() and category = "template" - ) - or - // Polymer templates - exists(HTML::Element elt | elt.getName() = "template" | - f = elt.getFile() and category = "template" - ) -} +import javascript +import ClassifyFiles from File f, string category where classify(f, category) diff --git a/javascript/ql/src/filters/ClassifyFiles.qll b/javascript/ql/src/filters/ClassifyFiles.qll new file mode 100644 index 00000000000..e59b13943b7 --- /dev/null +++ b/javascript/ql/src/filters/ClassifyFiles.qll @@ -0,0 +1,85 @@ +/** + * Provides classes and predicates for classifying files as containing + * generated code, test code, externs declarations, library code or + * template code. + */ + +import semmle.javascript.GeneratedCode +import semmle.javascript.frameworks.Testing +import semmle.javascript.frameworks.Templating +import semmle.javascript.dependencies.FrameworkLibraries + +/** + * Holds if `e` may be caused by parsing a template file as plain HTML or JavaScript. + * + * We use two heuristics: check for the presence of a known template delimiter preceding + * the error on the same line, and check whether the file name contains `template` or + * `templates`. + */ +predicate maybeCausedByTemplate(JSParseError e) { + exists(File f | f = e.getFile() | + e.getLine().indexOf(Templating::getADelimiter()) <= e.getLocation().getStartColumn() + or + f.getAbsolutePath().regexpMatch("(?i).*\\btemplates?\\b.*") + ) +} + +/** + * Holds if `e` is an expression in the form `o.p1.p2.p3....pn`. + */ +private predicate isNestedDotExpr(DotExpr e) { + e.getBase() instanceof VarAccess or + isNestedDotExpr(e.getBase()) +} + +/** + * Holds if `tl` only contains variable declarations and field reads. + */ +private predicate looksLikeExterns(TopLevel tl) { + forex(Stmt s | s.getParent() = tl | + exists(VarDeclStmt vds | vds = s | + forall(VariableDeclarator vd | vd = vds.getADecl() | not exists(vd.getInit())) + ) + or + isNestedDotExpr(s.(ExprStmt).getExpr()) + ) +} + +/** + * Holds if `f` is classified as belonging to `category`. + * + * There are currently four categories: + * - `"generated"`: `f` contains generated or minified code; + * - `"test"`: `f` contains test code; + * - `"externs"`: `f` contains externs declarations; + * - `"library"`: `f` contains library code; + * - `"template"`: `f` contains template code. + */ +predicate classify(File f, string category) { + isGenerated(f.getATopLevel()) and category = "generated" + or + ( + exists(Test t | t.getFile() = f) + or + exists(string stemExt | stemExt = "test" or stemExt = "spec" | + f = getTestFile(any(File orig), stemExt) + ) + or + f.getAbsolutePath().regexpMatch(".*/__(mocks|tests)__/.*") + ) and + category = "test" + or + (f.getATopLevel().isExterns() or looksLikeExterns(f.getATopLevel())) and + category = "externs" + or + f.getATopLevel() instanceof FrameworkLibraryInstance and category = "library" + or + exists(JSParseError err | maybeCausedByTemplate(err) | + f = err.getFile() and category = "template" + ) + or + // Polymer templates + exists(HTML::Element elt | elt.getName() = "template" | + f = elt.getFile() and category = "template" + ) +} diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 4b4e1a5e04f..e5171e83829 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -12,6 +12,7 @@ import semmle.javascript.Base64 import semmle.javascript.CFG import semmle.javascript.Classes import semmle.javascript.Closure +import semmle.javascript.Collections import semmle.javascript.Comments import semmle.javascript.Concepts import semmle.javascript.Constants @@ -36,6 +37,7 @@ import semmle.javascript.JsonParsers import semmle.javascript.JSX import semmle.javascript.Lines import semmle.javascript.Locations +import semmle.javascript.MembershipCandidates import semmle.javascript.Modules import semmle.javascript.NodeJS import semmle.javascript.NPM diff --git a/javascript/ql/src/localDefinitions.ql b/javascript/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..fb687ee13f1 --- /dev/null +++ b/javascript/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 js/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/javascript/ql/src/localReferences.ql b/javascript/ql/src/localReferences.ql new file mode 100644 index 00000000000..334fcaf72f2 --- /dev/null +++ b/javascript/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 js/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/javascript/ql/src/meta/Sanity.ql b/javascript/ql/src/meta/Consistency.ql similarity index 90% rename from javascript/ql/src/meta/Sanity.ql rename to javascript/ql/src/meta/Consistency.ql index d849bb38b88..61ee64b035f 100644 --- a/javascript/ql/src/meta/Sanity.ql +++ b/javascript/ql/src/meta/Consistency.ql @@ -5,8 +5,8 @@ * results. * @kind table * @problem.severity error - * @id js/sanity/api-contracts - * @tags sanity + * @id js/consistency/api-contracts + * @tags consistency */ import javascript @@ -66,7 +66,7 @@ predicate uniqueness_error(int number, string what, string problem) { * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information where possible. */ -predicate ast_sanity(string clsname, string problem, string what) { +predicate ast_consistency(string clsname, string problem, string what) { exists(Locatable l | clsname = l.getAQlClass() | uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.getLocation() or @@ -120,7 +120,7 @@ predicate ast_sanity(string clsname, string problem, string what) { * Holds if a location entity of QL class `clsname` does not have a unique `toString`, * where `problem` describes the problem and `what` gives location information where possible. */ -predicate location_sanity(string clsname, string problem, string what) { +predicate location_consistency(string clsname, string problem, string what) { exists(Location l | clsname = l.getAQlClass() | uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l or @@ -138,7 +138,7 @@ predicate hasCFG(StmtContainer sc) { not exists(Error err | err.getFile() = sc.g * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information. */ -predicate cfg_sanity(string clsname, string problem, string what) { +predicate cfg_consistency(string clsname, string problem, string what) { exists(StmtContainer cont | clsname = cont.getAQlClass() and hasCFG(cont) | uniqueness_error(count(cont.getEntry()), "getEntry", problem) and what = "at " + cont.getLocation() @@ -158,7 +158,7 @@ predicate cfg_sanity(string clsname, string problem, string what) { * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information. */ -predicate scope_sanity(string clsname, string problem, string what) { +predicate scope_consistency(string clsname, string problem, string what) { exists(Scope s | clsname = s.getAQlClass() | uniqueness_error(count(s.toString()), "toString", problem) and what = "a scope" or @@ -180,7 +180,7 @@ predicate scope_sanity(string clsname, string problem, string what) { * Holds if a JSDoc type expression of QL class `clsname` does not have a unique `toString`, * where `problem` describes the problem and `what` is the empty string. */ -predicate jsdoc_sanity(string clsname, string problem, string what) { +predicate jsdoc_consistency(string clsname, string problem, string what) { exists(JSDocTypeExprParent jsdtep | clsname = jsdtep.getAQlClass() | uniqueness_error(count(jsdtep.toString()), "toString", problem) and what = "" ) @@ -190,7 +190,7 @@ predicate jsdoc_sanity(string clsname, string problem, string what) { * Holds if a variable reference does not refer to a unique variable, * where `problem` describes the problem and `what` is the name of the variable. */ -predicate varref_sanity(string clsname, string problem, string what) { +predicate varref_consistency(string clsname, string problem, string what) { exists(VarRef vr, int n | n = count(vr.getVariable()) and n != 1 | clsname = vr.getAQlClass() and what = vr.getName() and @@ -200,10 +200,10 @@ predicate varref_sanity(string clsname, string problem, string what) { from string clsname, string problem, string what where - ast_sanity(clsname, problem, what) or - location_sanity(clsname, problem, what) or - scope_sanity(clsname, problem, what) or - cfg_sanity(clsname, problem, what) or - jsdoc_sanity(clsname, problem, what) or - varref_sanity(clsname, problem, what) + ast_consistency(clsname, problem, what) or + location_consistency(clsname, problem, what) or + scope_consistency(clsname, problem, what) or + cfg_consistency(clsname, problem, what) or + jsdoc_consistency(clsname, problem, what) or + varref_consistency(clsname, problem, what) select clsname + " " + what + " has " + problem diff --git a/javascript/ql/src/meta/SSA/DeadDef.ql b/javascript/ql/src/meta/SSA/DeadDef.ql index 3586b997ff7..d91da93ba2a 100644 --- a/javascript/ql/src/meta/SSA/DeadDef.ql +++ b/javascript/ql/src/meta/SSA/DeadDef.ql @@ -3,8 +3,8 @@ * @description Each SSA definition should have at least one use. * @kind problem * @problem.severity error - * @id js/sanity/dead-ssa-definition - * @tags sanity + * @id js/consistency/dead-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/Dominance.ql b/javascript/ql/src/meta/SSA/Dominance.ql index 98bf1a77545..11d112c0b93 100644 --- a/javascript/ql/src/meta/SSA/Dominance.ql +++ b/javascript/ql/src/meta/SSA/Dominance.ql @@ -4,8 +4,8 @@ * definition. * @kind problem * @problem.severity error - * @id js/sanity/non-dominating-ssa-definition - * @tags sanity + * @id js/consistency/non-dominating-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/MultipleDefs.ql b/javascript/ql/src/meta/SSA/MultipleDefs.ql index cde21fda37f..9a97624a540 100644 --- a/javascript/ql/src/meta/SSA/MultipleDefs.ql +++ b/javascript/ql/src/meta/SSA/MultipleDefs.ql @@ -4,8 +4,8 @@ * exactly one SSA variable. * @kind problem * @problem.severity error - * @id js/sanity/ambiguous-ssa-definition - * @tags sanity + * @id js/consistency/ambiguous-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql b/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql index cd84355f88c..29b849c2273 100644 --- a/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql +++ b/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA refinement node should have exactly one input. * @kind problem * @problem.severity error - * @id js/sanity/ambiguous-refinement-node - * @tags sanity + * @id js/consistency/ambiguous-refinement-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoDefs.ql b/javascript/ql/src/meta/SSA/NoDefs.ql index 4c4939f9dd2..43ede39870e 100644 --- a/javascript/ql/src/meta/SSA/NoDefs.ql +++ b/javascript/ql/src/meta/SSA/NoDefs.ql @@ -4,8 +4,8 @@ * exactly one SSA variable. * @kind problem * @problem.severity error - * @id js/sanity/dead-ssa-use - * @tags sanity + * @id js/consistency/dead-ssa-use + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoPhiInputs.ql b/javascript/ql/src/meta/SSA/NoPhiInputs.ql index d107b7edb17..f821acb7228 100644 --- a/javascript/ql/src/meta/SSA/NoPhiInputs.ql +++ b/javascript/ql/src/meta/SSA/NoPhiInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA phi node should have two or more inputs. * @kind problem * @problem.severity error - * @id js/sanity/dead-phi-node - * @tags sanity + * @id js/consistency/dead-phi-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoRefinementInputs.ql b/javascript/ql/src/meta/SSA/NoRefinementInputs.ql index dd314bde955..0a8470b2077 100644 --- a/javascript/ql/src/meta/SSA/NoRefinementInputs.ql +++ b/javascript/ql/src/meta/SSA/NoRefinementInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA refinement node should have exactly one input. * @kind problem * @problem.severity error - * @id js/sanity/dead-refinement-node - * @tags sanity + * @id js/consistency/dead-refinement-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/SinglePhiInput.ql b/javascript/ql/src/meta/SSA/SinglePhiInput.ql index 2ab7f329f52..8a1b4055b3a 100644 --- a/javascript/ql/src/meta/SSA/SinglePhiInput.ql +++ b/javascript/ql/src/meta/SSA/SinglePhiInput.ql @@ -3,8 +3,8 @@ * @description Every SSA phi node should have two or more inputs. * @kind problem * @problem.severity error - * @id js/sanity/trivial-phi-node - * @tags sanity + * @id js/consistency/trivial-phi-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index 799db5e0fb5..49e0d8a9c39 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -192,7 +192,7 @@ private class AmdDependencyPath extends PathExprCandidate { } /** A constant path element appearing in an AMD dependency expression. */ -private class ConstantAmdDependencyPathElement extends PathExprInModule, ConstantString { +private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString { ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() } override string getValue() { result = getStringValue() } @@ -259,8 +259,7 @@ private class AmdDependencyImport extends Import { * Gets the module whose absolute path matches this import, if there is only a single such module. */ private Module resolveByAbsolutePath() { - count(guessTarget()) = 1 and - result.getFile() = guessTarget() + result.getFile() = unique(File file | file = guessTarget()) } override Module getImportedModule() { @@ -290,7 +289,8 @@ private class AmdDependencyImport extends Import { * ``` */ class AmdModule extends Module { - AmdModule() { strictcount(AmdModuleDefinition def | amdModuleTopLevel(def, this)) = 1 } + cached + AmdModule() { exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this))) } /** Gets the definition of this module. */ AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) } diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index b1cbe224764..594ed6b6013 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -3,6 +3,7 @@ */ import javascript +private import internal.StmtContainers /** * A program element corresponding to JavaScript code, such as an expression @@ -20,9 +21,13 @@ import javascript * abs(-42); * ``` */ -class ASTNode extends @ast_node, Locatable { +class ASTNode extends @ast_node, NodeInStmtContainer { override Location getLocation() { hasLocation(this, result) } + override File getFile() { + result = getLocation().getFile() // Specialized for performance reasons + } + /** Gets the first token belonging to this element. */ Token getFirstToken() { exists(Location l1, Location l2 | @@ -121,6 +126,42 @@ class ASTNode extends @ast_node, Locatable { /** Holds if this syntactic entity belongs to an externs file. */ predicate inExternsFile() { getTopLevel().isExterns() } + /** + * Holds if this is an ambient node that is not a `TypeExpr` and is not inside a `.d.ts` file + * + * Since the overwhelming majority of ambient nodes are `TypeExpr` or inside `.d.ts` files, + * we avoid caching them. + */ + cached + private predicate isAmbientInternal() { + getParent().isAmbientInternal() + or + not isAmbientTopLevel(getTopLevel()) and + ( + this instanceof ExternalModuleDeclaration + or + this instanceof GlobalAugmentationDeclaration + or + this instanceof ExportAsNamespaceDeclaration + or + this instanceof TypeAliasDeclaration + or + this instanceof InterfaceDeclaration + or + hasDeclareKeyword(this) + or + hasTypeKeyword(this) + or + // An export such as `export declare function f()` should be seen as ambient. + hasDeclareKeyword(this.(ExportNamedDeclaration).getOperand()) + or + exists(Function f | + this = f and + not f.hasBody() + ) + ) + } + /** * Holds if this is part of an ambient declaration or type annotation in a TypeScript file. * @@ -130,9 +171,22 @@ class ASTNode extends @ast_node, Locatable { * The TypeScript compiler emits no code for ambient declarations, but they * can affect name resolution and type checking at compile-time. */ - predicate isAmbient() { getParent().isAmbient() } + pragma[inline] + predicate isAmbient() { + isAmbientInternal() + or + isAmbientTopLevel(getTopLevel()) + or + this instanceof TypeExpr + } } +/** + * Holds if the given file is a `.d.ts` file. + */ +cached +private predicate isAmbientTopLevel(TopLevel tl) { tl.getFile().getBaseName().matches("%.d.ts") } + /** * A toplevel syntactic unit; that is, a stand-alone script, an inline script * embedded in an HTML `