diff --git a/.gitignore b/.gitignore index d020f307ebc..b14dab0a6b1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,5 @@ # It's useful (though not required) to be able to unpack codeql in the ql checkout itself /codeql/ -.vscode/settings.json + csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json 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 af8575bc316..6b6cffedcaf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to CodeQL -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! +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). @@ -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. @@ -36,7 +36,7 @@ If you have an idea for a query that you would like to share with other CodeQL u 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** @@ -47,10 +47,6 @@ If you have an idea for a query that you would like to share with other CodeQL u - The query must have at least one true positive result on some revision of a real project. -6. **Contributor License Agreement** - - - The contributor can satisfy the [CLA](#contributor-license-agreement). - Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). @@ -65,33 +61,6 @@ 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@semmle.com) if you have any questions about +Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies. -## Contributor License Agreement - -This Contributor License Agreement (“Agreement”) is entered into between Semmle Limited (“Semmle,” “we” or “us” etc.), and You (as defined and further identified below). - -Accordingly, You hereby agree to the following terms for Your present and future Contributions submitted to Semmle: - -1. **Definitions**. - - * "You" (or "Your") shall mean the Contribution copyright owner (whether an individual or organization) or legal entity authorized by the copyright owner that is making this Agreement with Semmle. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. 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. - - * "Contribution(s)" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, submitted by You to Semmle for inclusion in, or documentation of, any of the products or projects owned or managed by Semmle (the "Work(s)"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Semmle 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, Semmle for the purpose of discussing and/or improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." - -2. **Grant of Copyright License**. You hereby grant to Semmle and to recipients of software distributed by Semmle 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 Your Contributions and such derivative works. - -3. **Grant of Patent License**. You hereby grant to Semmle and to recipients of software distributed by Semmle 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 You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or the Work to which You have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. - -4. **Ownership**. Except as set out above, You keep all right, title, and interest in Your Contribution. The rights that You grant to us under this Agreement are effective on the date You first submitted a Contribution to us, even if Your submission took place before the date You entered this Agreement. - -5. **Representations**. You represent and warrant that: (i) the Contributions are an original work and that You can legally grant the rights set out in this Agreement; (ii) the Contributions and Semmle’s exercise of any license rights granted hereunder, does not and will not, infringe the rights of any third party; (iii) You are not aware of any pending or threatened claims, suits, actions, or charges pertaining to the Contributions, including without limitation any claims or allegations that any or all of the Contributions infringes, violates, or misappropriate the intellectual property rights of any third party (You further agree that You will notify Semmle immediately if You become aware of any such actual or potential claims, suits, actions, allegations or charges). - -6. **Employer**. If Your employer(s) has rights to intellectual property that You create that includes Your Contributions, You represent and warrant that Your employer has waived such rights for Your Contributions to Semmle, or that You have received permission to make Contributions on behalf of that employer and that You are authorized to execute this Agreement on behalf of Your employer. - -7. **Inclusion of Code**. We determine the code that is in our Works. You understand that the decision to include the Contribution in any project or source repository is entirely that of Semmle, and this agreement does not guarantee that the Contributions will be included in any product. - -8. **Disclaimer**. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Except as set forth herein, and unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. - -9. **General**. The failure of either party to enforce its rights under this Agreement for any period shall not be construed as a waiver of such rights. No changes or modifications or waivers to this Agreement will be effective unless in writing and signed by both parties. In the event that any provision of this Agreement shall be determined to be illegal or unenforceable, that provision will be limited or eliminated to the minimum extent necessary so that this Agreement shall otherwise remain in full force and effect and enforceable. This Agreement shall be governed by and construed in accordance with the laws of the State of California in the United States without regard to the conflicts of laws provisions thereof. In any action or proceeding to enforce rights under this Agreement, the prevailing party will be entitled to recover costs and attorneys’ fees. diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index 65d947ff274..00000000000 --- a/COPYRIGHT +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) Semmle Inc and other contributors. All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. diff --git a/LICENSE b/LICENSE index d9a10c0d8e8..e29b05cd648 100644 --- a/LICENSE +++ b/LICENSE @@ -1,176 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (c) 2006-2020 GitHub, Inc. - 1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - "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 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 1f77856cfc4..19d38c3b40a 100644 --- a/README.md +++ b/README.md @@ -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 2b53e6d56aa..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,44 +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. | +| 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. + * 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-csharp.md b/change-notes/1.25/analysis-csharp.md new file mode 100644 index 00000000000..fe19c1d8b20 --- /dev/null +++ b/change-notes/1.25/analysis-csharp.md @@ -0,0 +1,28 @@ +# 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 + +## 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 construced 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`.) + +## Changes to autobuilder diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md new file mode 100644 index 00000000000..6e759b62868 --- /dev/null +++ b/change-notes/1.25/analysis-javascript.md @@ -0,0 +1,27 @@ +# Improvements to JavaScript analysis + +## General improvements + +* Support for the following frameworks and libraries has been improved: + - [jGrowl](https://github.com/stanlemon/jGrowl) + - [jQuery](https://jquery.com/) + +## 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. | + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|--------------------------------|------------------------------|---------------------------------------------------------------------------| +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | + +## Changes to libraries + +* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module. diff --git a/config/sync-files.py b/config/sync-files.py index 30be173c18b..e667907b12c 100644 --- a/config/sync-files.py +++ b/config/sync-files.py @@ -107,7 +107,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 d548aca26e7..44557503e43 100644 --- a/cpp/ql/src/Critical/MemoryFreed.qll +++ b/cpp/ql/src/Critical/MemoryFreed.qll @@ -4,15 +4,24 @@ private predicate freed(Expr e) { e = any(DeallocationExpr de).getFreedExpr() or exists(ExprCall c | - // cautiously assume that any ExprCall could be a freeCall. + // cautiously assume that any `ExprCall` could be a deallocation expression. c.getAnArgument() = 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/Critical/NewDelete.qll b/cpp/ql/src/Critical/NewDelete.qll index 9dd55525b59..30b9f9ad94a 100644 --- a/cpp/ql/src/Critical/NewDelete.qll +++ b/cpp/ql/src/Critical/NewDelete.qll @@ -5,17 +5,34 @@ import cpp import semmle.code.cpp.controlflow.SSA import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.models.implementations.Allocation +import semmle.code.cpp.models.implementations.Deallocation /** * Holds if `alloc` is a use of `malloc` or `new`. `kind` is * a string describing the type of the allocation. */ predicate allocExpr(Expr alloc, string kind) { - isAllocationExpr(alloc) and - not alloc.isFromUninstantiatedTemplate(_) and ( - alloc instanceof FunctionCall and - kind = "malloc" + exists(Function target | + alloc.(AllocationExpr).(FunctionCall).getTarget() = target and + ( + target.getName() = "operator new" and + kind = "new" and + // exclude placement new and custom overloads as they + // may not conform to assumptions + not target.getNumberOfParameters() > 1 + or + target.getName() = "operator new[]" and + kind = "new[]" and + // exclude placement new and custom overloads as they + // may not conform to assumptions + not target.getNumberOfParameters() > 1 + or + not target instanceof OperatorNewAllocationFunction and + kind = "malloc" + ) + ) or alloc instanceof NewExpr and kind = "new" and @@ -28,7 +45,8 @@ predicate allocExpr(Expr alloc, string kind) { // exclude placement new and custom overloads as they // may not conform to assumptions not alloc.(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1 - ) + ) and + not alloc.isFromUninstantiatedTemplate(_) } /** @@ -110,8 +128,20 @@ predicate allocReaches(Expr e, Expr alloc, string kind) { * describing the type of that free or delete. */ predicate freeExpr(Expr free, Expr freed, string kind) { - freeCall(free, freed) and - kind = "free" + exists(Function target | + freed = free.(DeallocationExpr).getFreedExpr() and + free.(FunctionCall).getTarget() = target and + ( + target.getName() = "operator delete" and + kind = "delete" + or + target.getName() = "operator delete[]" and + kind = "delete[]" + or + not target instanceof OperatorDeleteDeallocationFunction and + kind = "free" + ) + ) or free.(DeleteExpr).getExpr() = freed and kind = "delete" 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/Protocols/TlsSettingsMisconfiguration.ql b/cpp/ql/src/Likely Bugs/Protocols/TlsSettingsMisconfiguration.ql index fb7edce038c..04b3d13a3f7 100644 --- a/cpp/ql/src/Likely Bugs/Protocols/TlsSettingsMisconfiguration.ql +++ b/cpp/ql/src/Likely Bugs/Protocols/TlsSettingsMisconfiguration.ql @@ -3,7 +3,7 @@ * @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols. * @kind problem * @problem.severity error - * @id cpp/boost/tls_settings_misconfiguration + * @id cpp/boost/tls-settings-misconfiguration * @tags security */ diff --git a/cpp/ql/src/Likely Bugs/ReturnConstTypeMember.cpp b/cpp/ql/src/Likely Bugs/ReturnConstTypeMember.cpp index cc6b6da3abb..ad3d7d3c9e1 100644 --- a/cpp/ql/src/Likely Bugs/ReturnConstTypeMember.cpp +++ b/cpp/ql/src/Likely Bugs/ReturnConstTypeMember.cpp @@ -8,6 +8,6 @@ struct S { // Whereas here it does make a semantic difference. auto getValCorrect() const -> int { - return val + return val; } }; 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/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-022/TaintedPath.ql b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 42a29b96268..496b957cca3 100644 --- a/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/cpp/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -2,7 +2,7 @@ * @name Uncontrolled data used in path expression * @description Accessing paths influenced by users can allow an * attacker to access unexpected resources. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/path-injection @@ -17,6 +17,7 @@ import cpp import semmle.code.cpp.security.FunctionWithWrappers import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTracking +import TaintedWithPath /** * A function for opening a file. @@ -51,12 +52,19 @@ class FileFunction extends FunctionWithWrappers { override predicate interestingArg(int arg) { arg = 0 } } +class TaintedPathConfiguration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(FileFunction fileFunction | fileFunction.outermostWrapperFunctionCall(tainted, _)) + } +} + from - FileFunction fileFunction, Expr taintedArg, Expr taintSource, string taintCause, string callChain + FileFunction fileFunction, Expr taintedArg, Expr taintSource, PathNode sourceNode, + PathNode sinkNode, string taintCause, string callChain where fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and - tainted(taintSource, taintedArg) and + taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and isUserInput(taintSource, taintCause) -select taintedArg, +select taintedArg, sourceNode, sinkNode, "This argument to a file access function is derived from $@ and then passed to " + callChain, taintSource, "user input (" + taintCause + ")" diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 8b7fb83df81..0e0c4add7f6 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -2,7 +2,7 @@ * @name CGI script vulnerable to cross-site scripting * @description Writing user input directly to a web page * allows for a cross-site scripting vulnerability. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cpp/cgi-xss @@ -13,6 +13,7 @@ import cpp import semmle.code.cpp.commons.Environment import semmle.code.cpp.security.TaintTracking +import TaintedWithPath /** A call that prints its arguments to `stdout`. */ class PrintStdoutCall extends FunctionCall { @@ -27,8 +28,13 @@ class QueryString extends EnvironmentRead { QueryString() { getEnvironmentVariable() = "QUERY_STRING" } } -from QueryString query, PrintStdoutCall call, Element printedArg -where - call.getAnArgument() = printedArg and - tainted(query, printedArg) -select printedArg, "Cross-site scripting vulnerability due to $@.", query, "this query data" +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(PrintStdoutCall call | call.getAnArgument() = tainted) + } +} + +from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode +where taintedWithPath(query, printedArg, sourceNode, sinkNode) +select printedArg, sourceNode, sinkNode, "Cross-site scripting vulnerability due to $@.", query, + "this query data" diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index 3f234dd0678..de786d22f30 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -3,7 +3,7 @@ * @description Including user-supplied data in a SQL query without * neutralizing special elements can make code vulnerable * to SQL Injection. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cpp/sql-injection @@ -15,6 +15,7 @@ import cpp import semmle.code.cpp.security.Security import semmle.code.cpp.security.FunctionWithWrappers import semmle.code.cpp.security.TaintTracking +import TaintedWithPath class SQLLikeFunction extends FunctionWithWrappers { SQLLikeFunction() { sqlArgument(this.getName(), _) } @@ -22,11 +23,19 @@ class SQLLikeFunction extends FunctionWithWrappers { override predicate interestingArg(int arg) { sqlArgument(this.getName(), arg) } } -from SQLLikeFunction runSql, Expr taintedArg, Expr taintSource, string taintCause, string callChain +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _)) + } +} + +from + SQLLikeFunction runSql, Expr taintedArg, Expr taintSource, PathNode sourceNode, PathNode sinkNode, + string taintCause, string callChain where runSql.outermostWrapperFunctionCall(taintedArg, callChain) and - tainted(taintSource, taintedArg) and + taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and isUserInput(taintSource, taintCause) -select taintedArg, +select taintedArg, sourceNode, sinkNode, "This argument to a SQL query function is derived from $@ and then passed to " + callChain, taintSource, "user input (" + taintCause + ")" diff --git a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql index 233fe34e6bf..943c13f9c5d 100644 --- a/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql +++ b/cpp/ql/src/Security/CWE/CWE-114/UncontrolledProcessOperation.ql @@ -3,7 +3,7 @@ * @description Using externally controlled strings in a process * operation can allow an attacker to execute malicious * commands. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/uncontrolled-process-operation @@ -14,13 +14,24 @@ import cpp import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTracking +import TaintedWithPath -from string processOperation, int processOperationArg, FunctionCall call, Expr arg, Element source +predicate isProcessOperationExplanation(Expr arg, string processOperation) { + exists(int processOperationArg, FunctionCall call | + isProcessOperationArgument(processOperation, processOperationArg) and + call.getTarget().getName() = processOperation and + call.getArgument(processOperationArg) = arg + ) +} + +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) } +} + +from string processOperation, Expr arg, Expr source, PathNode sourceNode, PathNode sinkNode where - isProcessOperationArgument(processOperation, processOperationArg) and - call.getTarget().getName() = processOperation and - call.getArgument(processOperationArg) = arg and - tainted(source, arg) -select arg, + isProcessOperationExplanation(arg, processOperation) and + taintedWithPath(source, arg, sourceNode, sinkNode) +select arg, sourceNode, sinkNode, "The value of this argument may come from $@ and is being passed to " + processOperation, source, source.toString() diff --git a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql index ff136d2c06b..f1a8b4e8544 100644 --- a/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql +++ b/cpp/ql/src/Security/CWE/CWE-120/UnboundedWrite.ql @@ -2,7 +2,7 @@ * @name Unbounded write * @description Buffer write operations that do not control the length * of data written may overflow. - * @kind problem + * @kind path-problem * @problem.severity error * @precision medium * @id cpp/unbounded-write @@ -16,6 +16,7 @@ import semmle.code.cpp.security.BufferWrite import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTracking +import TaintedWithPath /* * --- Summary of CWE-120 alerts --- @@ -54,32 +55,48 @@ predicate isUnboundedWrite(BufferWrite bw) { * } */ +/** + * Holds if `e` is a source buffer going into an unbounded write `bw` or a + * qualifier of (a qualifier of ...) such a source. + */ +predicate unboundedWriteSource(Expr e, BufferWrite bw) { + isUnboundedWrite(bw) and e = bw.getASource() + or + exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier()) +} + /* * --- user input reach --- */ -/** - * Identifies expressions that are potentially tainted with user - * input. Most of the work for this is actually done by the - * TaintTracking library. - */ -predicate tainted2(Expr expr, Expr inputSource, string inputCause) { - taintedIncludingGlobalVars(inputSource, expr, _) and - inputCause = inputSource.toString() - or - exists(Expr e | tainted2(e, inputSource, inputCause) | - // field accesses of a tainted struct are tainted - e = expr.(FieldAccess).getQualifier() - ) +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { unboundedWriteSource(tainted, _) } + + override predicate taintThroughGlobals() { any() } } /* * --- put it together --- */ -from BufferWrite bw, Expr inputSource, string inputCause +/* + * An unbounded write is, for example `strcpy(..., tainted)`. We're looking + * for a tainted source buffer of an unbounded write, where this source buffer + * is a sink in the taint-tracking analysis. + * + * In the case of `gets` and `scanf`, where the source buffer is implicit, the + * `BufferWrite` library reports the source buffer to be the same as the + * destination buffer. Since those destination-buffer arguments are also + * modeled in the taint-tracking library as being _sources_ of taint, they are + * in practice reported as being tainted because the `security.TaintTracking` + * library does not distinguish between taint going into an argument and out of + * an argument. Thus, we get the desired alerts. + */ + +from BufferWrite bw, Expr inputSource, Expr tainted, PathNode sourceNode, PathNode sinkNode where - isUnboundedWrite(bw) and - tainted2(bw.getASource(), inputSource, inputCause) -select bw, "This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", - inputSource, inputCause + taintedWithPath(inputSource, tainted, sourceNode, sinkNode) and + unboundedWriteSource(tainted, bw) +select bw, sourceNode, sinkNode, + "This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", inputSource, + inputSource.toString() diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 02a0f42fa6b..91ccc5c4d40 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -3,7 +3,7 @@ * @description Using externally-controlled format strings in * printf-style functions can lead to buffer overflows * or data representation problems. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/tainted-format-string @@ -16,12 +16,21 @@ import cpp import semmle.code.cpp.security.Security import semmle.code.cpp.security.FunctionWithWrappers import semmle.code.cpp.security.TaintTracking +import TaintedWithPath -from PrintfLikeFunction printf, Expr arg, string printfFunction, Expr userValue, string cause +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _)) + } +} + +from + PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode, + string printfFunction, Expr userValue, string cause where printf.outermostWrapperFunctionCall(arg, printfFunction) and - tainted(userValue, arg) and + taintedWithPath(userValue, arg, sourceNode, sinkNode) and isUserInput(userValue, cause) -select arg, +select arg, sourceNode, sinkNode, "The value of this argument may come from $@ and is being used as a formatting argument to " + printfFunction, userValue, cause diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql index f3cb4fcf1bb..96cffdb024b 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql @@ -3,7 +3,7 @@ * @description Using externally-controlled format strings in * printf-style functions can lead to buffer overflows * or data representation problems. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/tainted-format-string-through-global @@ -16,15 +16,24 @@ import cpp import semmle.code.cpp.security.FunctionWithWrappers import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTracking +import TaintedWithPath + +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { + exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _)) + } + + override predicate taintThroughGlobals() { any() } +} from - PrintfLikeFunction printf, Expr arg, string printfFunction, Expr userValue, string cause, - string globalVar + PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode, + string printfFunction, Expr userValue, string cause where printf.outermostWrapperFunctionCall(arg, printfFunction) and - not tainted(_, arg) and - taintedIncludingGlobalVars(userValue, arg, globalVar) and + not taintedWithoutGlobals(arg) and + taintedWithPath(userValue, arg, sourceNode, sinkNode) and isUserInput(userValue, cause) -select arg, - "This value may flow through $@, originating from $@, and is a formatting argument to " + - printfFunction + ".", globalVarFromId(globalVar), globalVar, userValue, cause +select arg, sourceNode, sinkNode, + "The value of this argument may come from $@ and is being used as a formatting argument to " + + printfFunction, userValue, cause diff --git a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql index 8013fbcf614..a4b0f131d14 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql @@ -2,7 +2,7 @@ * @name Uncontrolled data in arithmetic expression * @description Arithmetic operations on uncontrolled data that is not * validated can cause overflows. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/uncontrolled-arithmetic @@ -15,6 +15,7 @@ import cpp import semmle.code.cpp.security.Overflow import semmle.code.cpp.security.Security import semmle.code.cpp.security.TaintTracking +import TaintedWithPath predicate isRandCall(FunctionCall fc) { fc.getTarget().getName() = "rand" } @@ -40,9 +41,22 @@ class SecurityOptionsArith extends SecurityOptions { } } -predicate taintedVarAccess(Expr origin, VariableAccess va) { - isUserInput(origin, _) and - tainted(origin, va) +predicate isDiv(VariableAccess va) { exists(AssignDivExpr div | div.getLValue() = va) } + +predicate missingGuard(VariableAccess va, string effect) { + exists(Operation op | op.getAnOperand() = va | + missingGuardAgainstUnderflow(op, va) and effect = "underflow" + or + missingGuardAgainstOverflow(op, va) and effect = "overflow" + ) +} + +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element e) { + isDiv(e) + or + missingGuard(e, _) + } } /** @@ -50,19 +64,17 @@ predicate taintedVarAccess(Expr origin, VariableAccess va) { * range. */ predicate guardedByAssignDiv(Expr origin) { - isUserInput(origin, _) and - exists(AssignDivExpr div, VariableAccess va | tainted(origin, va) and div.getLValue() = va) + exists(VariableAccess va | + taintedWithPath(origin, va, _, _) and + isDiv(va) + ) } -from Expr origin, Operation op, VariableAccess va, string effect +from Expr origin, VariableAccess va, string effect, PathNode sourceNode, PathNode sinkNode where - taintedVarAccess(origin, va) and - op.getAnOperand() = va and - ( - missingGuardAgainstUnderflow(op, va) and effect = "underflow" - or - missingGuardAgainstOverflow(op, va) and effect = "overflow" - ) and + taintedWithPath(origin, va, sourceNode, sinkNode) and + missingGuard(va, effect) and not guardedByAssignDiv(origin) -select va, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", - origin, "Uncontrolled value" +select va, sourceNode, sinkNode, + "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin, + "Uncontrolled value" diff --git a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql index 85248a26d19..54c6d1e7a96 100644 --- a/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql +++ b/cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql @@ -2,7 +2,7 @@ * @name Overflow in uncontrolled allocation size * @description Allocating memory with a size controlled by an external * user can result in integer overflow. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cpp/uncontrolled-allocation-size @@ -13,21 +13,33 @@ import cpp import semmle.code.cpp.security.TaintTracking +import TaintedWithPath -predicate taintedAllocSize(Expr e, Expr source, string taintCause) { - ( - isAllocationExpr(e) or - any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e - ) 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) { allocSink(_, tainted) } +} + +predicate taintedAllocSize( + Expr source, Expr alloc, PathNode sourceNode, PathNode sinkNode, string taintCause +) { + isUserInput(source, taintCause) and exists(Expr tainted | - tainted = e.getAChild() and - tainted.getUnspecifiedType() instanceof IntegralType and - isUserInput(source, taintCause) and - tainted(source, tainted) + allocSink(alloc, tainted) and + taintedWithPath(source, tainted, sourceNode, sinkNode) ) } -from Expr e, Expr source, string taintCause -where taintedAllocSize(e, source, taintCause) -select e, "This allocation size is derived from $@ and might overflow", source, - "user input (" + taintCause + ")" +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-290/AuthenticationBypass.ql b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql index 19bee24a16d..80b5ee49e97 100644 --- a/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql +++ b/cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql @@ -3,7 +3,7 @@ * @description Authentication by checking that the peer's address * matches a known IP or web address is unsafe as it is * vulnerable to spoofing attacks. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/user-controlled-bypass @@ -12,6 +12,7 @@ */ import semmle.code.cpp.security.TaintTracking +import TaintedWithPath predicate hardCodedAddressOrIP(StringLiteral txt) { exists(string s | s = txt.getValueText() | @@ -102,16 +103,21 @@ predicate useOfHardCodedAddressOrIP(Expr use) { * untrusted input then it might be vulnerable to a spoofing * attack. */ -predicate hardCodedAddressInCondition(Expr source, Expr condition) { - // One of the sub-expressions of the condition is tainted. - exists(Expr taintedExpr | taintedExpr.getParent+() = condition | tainted(source, taintedExpr)) and +predicate hardCodedAddressInCondition(Expr subexpression, Expr condition) { + subexpression = condition.getAChild+() and // One of the sub-expressions of the condition is a hard-coded // IP or web-address. - exists(Expr use | use.getParent+() = condition | useOfHardCodedAddressOrIP(use)) and + exists(Expr use | use = condition.getAChild+() | useOfHardCodedAddressOrIP(use)) and condition = any(IfStmt ifStmt).getCondition() } -from Expr source, Expr condition -where hardCodedAddressInCondition(source, condition) -select condition, "Untrusted input $@ might be vulnerable to a spoofing attack.", source, - source.toString() +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element sink) { hardCodedAddressInCondition(sink, _) } +} + +from Expr subexpression, Expr source, Expr condition, PathNode sourceNode, PathNode sinkNode +where + hardCodedAddressInCondition(subexpression, condition) and + taintedWithPath(source, subexpression, sourceNode, sinkNode) +select condition, sourceNode, sinkNode, + "Untrusted input $@ might be vulnerable to a spoofing attack.", source, source.toString() diff --git a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql index aa153779df1..3e84c0a87d9 100644 --- a/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql +++ b/cpp/ql/src/Security/CWE/CWE-311/CleartextBufferWrite.ql @@ -2,7 +2,7 @@ * @name Cleartext storage of sensitive information in buffer * @description Storing sensitive information in cleartext can expose it * to an attacker. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/cleartext-storage-buffer @@ -14,12 +14,20 @@ import cpp import semmle.code.cpp.security.BufferWrite import semmle.code.cpp.security.TaintTracking import semmle.code.cpp.security.SensitiveExprs +import TaintedWithPath -from BufferWrite w, Expr taintedArg, Expr taintSource, string taintCause, SensitiveExpr dest +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { exists(BufferWrite w | w.getASource() = tainted) } +} + +from + BufferWrite w, Expr taintedArg, Expr taintSource, PathNode sourceNode, PathNode sinkNode, + string taintCause, SensitiveExpr dest where - tainted(taintSource, taintedArg) and + taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and isUserInput(taintSource, taintCause) and w.getASource() = taintedArg and dest = w.getDest() -select w, "This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", +select w, sourceNode, sinkNode, + "This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", taintSource, "user input (" + taintCause + ")" diff --git a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql index e4f1e9c834a..000833cbb58 100644 --- a/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql +++ b/cpp/ql/src/Security/CWE/CWE-313/CleartextSqliteDatabase.ql @@ -2,7 +2,7 @@ * @name Cleartext storage of sensitive information in an SQLite database * @description Storing sensitive information in a non-encrypted * database can expose it to an attacker. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/cleartext-storage-database @@ -13,6 +13,7 @@ import cpp import semmle.code.cpp.security.SensitiveExprs import semmle.code.cpp.security.TaintTracking +import TaintedWithPath class UserInputIsSensitiveExpr extends SecurityOptions { override predicate isUserInput(Expr expr, string cause) { @@ -32,10 +33,21 @@ predicate sqlite_encryption_used() { any(FunctionCall fc).getTarget().getName().matches("sqlite%\\_key\\_%") } -from SensitiveExpr taintSource, Expr taintedArg, SqliteFunctionCall sqliteCall +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element taintedArg) { + exists(SqliteFunctionCall sqliteCall | + taintedArg = sqliteCall.getASource() and + not sqlite_encryption_used() + ) + } +} + +from + SensitiveExpr taintSource, Expr taintedArg, SqliteFunctionCall sqliteCall, PathNode sourceNode, + PathNode sinkNode where - tainted(taintSource, taintedArg) and - taintedArg = sqliteCall.getASource() and - not sqlite_encryption_used() -select sqliteCall, "This SQLite call may store $@ in a non-encrypted SQLite database", taintSource, + taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and + taintedArg = sqliteCall.getASource() +select sqliteCall, sourceNode, sinkNode, + "This SQLite call may store $@ in a non-encrypted SQLite database", taintSource, "sensitive information" 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/Security/CWE/CWE-807/TaintedCondition.ql b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql index b940da029ec..e60f592b2af 100644 --- a/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql +++ b/cpp/ql/src/Security/CWE/CWE-807/TaintedCondition.ql @@ -3,7 +3,7 @@ * @description Using untrusted inputs in a statement that makes a * security decision makes code vulnerable to * attack. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision medium * @id cpp/tainted-permissions-check @@ -12,14 +12,9 @@ */ import semmle.code.cpp.security.TaintTracking +import TaintedWithPath -/** - * Holds if there is an 'if' statement whose condition `condition` - * is influenced by tainted data `source`, and the body contains - * `raise` which escalates privilege. - */ -predicate cwe807violation(Expr source, Expr condition, Expr raise) { - tainted(source, condition) and +predicate sensitiveCondition(Expr condition, Expr raise) { raisesPrivilege(raise) and exists(IfStmt ifstmt | ifstmt.getCondition() = condition and @@ -27,7 +22,19 @@ predicate cwe807violation(Expr source, Expr condition, Expr raise) { ) } -from Expr source, Expr condition, Expr raise -where cwe807violation(source, condition, raise) -select condition, "Reliance on untrusted input $@ to raise privilege at $@", source, - source.toString(), raise, raise.toString() +class Configuration extends TaintTrackingConfiguration { + override predicate isSink(Element tainted) { sensitiveCondition(tainted, _) } +} + +/* + * Produce an alert if there is an 'if' statement whose condition `condition` + * is influenced by tainted data `source`, and the body contains + * `raise` which escalates privilege. + */ + +from Expr source, Expr condition, Expr raise, PathNode sourceNode, PathNode sinkNode +where + taintedWithPath(source, condition, sourceNode, sinkNode) and + sensitiveCondition(condition, raise) +select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@", + source, source.toString(), raise, raise.toString() diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index 2036584e44c..e9fda1cdb9e 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -12,3 +12,8 @@ - Critical/FileNeverClosed.ql - Critical/MemoryMayNotBeFreed.ql - Critical/MemoryNeverFreed.ql +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references 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/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/qlpack.yml b/cpp/ql/src/qlpack.yml index a1c7df902de..45ae614f88e 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-cpp version: 0.0.0 dbscheme: semmlecode.cpp.dbscheme suites: codeql-suites +extractor: cpp diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 67a2d11ff24..5aa9f43f48b 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -458,6 +458,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 +909,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..7f961bfd6f6 100644 --- a/cpp/ql/src/semmle/code/cpp/Comments.qll +++ b/cpp/ql/src/semmle/code/cpp/Comments.qll @@ -13,8 +13,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..691c0e08de3 100644 --- a/cpp/ql/src/semmle/code/cpp/Compilation.qll +++ b/cpp/ql/src/semmle/code/cpp/Compilation.qll @@ -21,9 +21,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 +40,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..840705b01b5 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -25,7 +25,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. * @@ -161,6 +161,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 +304,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..37459602c03 100644 --- a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll +++ b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll @@ -11,6 +11,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/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 60ef2d587ef..2c81e768db7 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -3,7 +3,7 @@ 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 +28,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 +36,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 diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 9ed4b27f562..90998ed4ea3 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -103,6 +103,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 +118,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)`. diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..839a85d6b8f 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -130,7 +130,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) } } 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..4d546a736dc 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)) } /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll b/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll index a508c929d9a..a9597fc72b5 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Alloc.qll @@ -23,6 +23,8 @@ predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunctio /** * A call to a library routine that frees memory. + * + * DEPRECATED: Use `DeallocationExpr` instead (this also includes `delete` expressions). */ predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getFreedExpr() } 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/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..22e39f0b907 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -166,10 +166,13 @@ 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()) + or + e = call.getQualifier().getFullyConverted() and + e.getUnderlyingType() instanceof PointerType ) or exists(AssignExpr assign | e = assign.getRValue().getFullyConverted()) @@ -187,8 +190,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 +210,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 +272,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 +305,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/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index a1daeb66411..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..852f54974e2 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,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - 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. * * `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 any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) 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() - ) - 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()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) 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, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, 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, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) 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, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * 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). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - 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, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `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). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - 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, contentIn) 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(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ 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) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ 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 TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,8 +415,7 @@ 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 } } @@ -538,7 +423,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -678,6 +563,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 +585,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 +597,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 +611,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 +678,58 @@ 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())) + } +} + +/** + * 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(Content f) { this = TFrontHead(f) } +} + +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 } +} + +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 } +} + +/** 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..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..618c29ebb86 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -43,7 +43,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 @@ -299,7 +299,7 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo override Node getPreUpdateNode() { result.asExpr() = pd.getDefinedExpr() } - override Location getLocation() { result = pd.getLocation() } + override Location getLocation() { result = pd.getActualLocation() } PartialDefinition getPartialDefinition() { result = pd } @@ -496,8 +496,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 | ( @@ -657,7 +655,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..d35bc4533b9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -113,44 +113,39 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - private newtype TPartialDefinition = - TExplicitFieldStoreQualifier(Expr qualifier, ControlFlowNode node) { - exists(FieldAccess fa | qualifier = fa.getQualifier() | + private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) { + assignmentLikeOperation(node, _, fa, _) + } + + class PartialDefinition extends Expr { + ControlFlowNode node; + + PartialDefinition() { + exists(FieldAccess fa | this = fa.getQualifier() | + // `fa = ...`, `fa += ...`, etc. isInstanceFieldWrite(fa, node) or + // `fa.a = ...`, `f(&fa)`, etc. exists(PartialDefinition pd | node = pd.getSubBasicBlockStart() and fa = pd.getDefinedExpr() ) ) - } or - TExplicitCallQualifier(Expr qualifier) { + or + // `e.f(...)` exists(Call call | - qualifier = call.getQualifier() and + this = 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; - ControlFlowNode node; - - PartialDefinition() { - this = TExplicitFieldStoreQualifier(definedExpr, node) + ) and + node = this or - this = TExplicitCallQualifier(definedExpr) and node = definedExpr - or - this = TReferenceArgument(definedExpr, node) + // `f(e)`, `f(&e)`, etc. + referenceArgument(node, this) } - predicate partiallyDefines(Variable v) { definedExpr = v.getAnAccess() } + predicate partiallyDefines(Variable v) { this = v.getAnAccess() } - predicate partiallyDefinesThis(ThisExpr e) { definedExpr = e } + predicate partiallyDefinesThis(ThisExpr e) { this = e } /** * Gets the subBasicBlock where this `PartialDefinition` is defined. @@ -165,33 +160,29 @@ private module PartialDefinitions { * ``` * The expression `x` is being partially defined. */ - Expr getDefinedExpr() { result = definedExpr } + Expr getDefinedExpr() { result = this } - Location getLocation() { - not exists(definedExpr.getLocation()) and result = definedExpr.getParent().getLocation() + /** + * 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 - definedExpr.getLocation() instanceof UnknownLocation and - result = definedExpr.getParent().getLocation() + this.getLocation() instanceof UnknownLocation and + result = this.getParent().getLocation() or - result = definedExpr.getLocation() and not result instanceof UnknownLocation + result = this.getLocation() and not result instanceof UnknownLocation } - - string toString() { result = "partial def of " + definedExpr } } /** * A partial definition that's a definition by reference. */ - class DefinitionByReference extends PartialDefinition, TReferenceArgument { + class DefinitionByReference extends PartialDefinition { 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) - } + DefinitionByReference() { referenceArgument(va, this) } VariableAccess getVariableAccess() { result = va } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index f68eaef5d8b..86a46c2531d 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -338,7 +338,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/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 6eb4ed52319..d22e090a9e6 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)` diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 3a45d8597d5..0648e449157 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -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. @@ -699,7 +699,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 +762,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/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/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 10aa162e3e0..dbeefae4880 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -2,6 +2,7 @@ import cpp import semmle.code.cpp.security.Security private import semmle.code.cpp.ir.dataflow.DataFlow 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.models.interfaces.Taint @@ -143,7 +144,17 @@ private predicate writesVariable(StoreInstruction store, Variable var) { } /** - * A variable that has any kind of upper-bound check anywhere in the program + * A variable that has any kind of upper-bound check anywhere in the program. This is + * biased towards being inclusive because there are a lot of valid ways of doing an + * upper bounds checks if we don't consider where it occurs, for example: + * ``` + * if (x < 10) { sink(x); } + * + * if (10 > y) { sink(y); } + * + * if (z > 10) { z = 10; } + * sink(z); + * ``` */ // TODO: This coarse overapproximation, ported from the old taint tracking // library, could be replaced with an actual semantic check that a particular @@ -152,10 +163,10 @@ private predicate writesVariable(StoreInstruction store, Variable var) { // previously suppressed by this predicate by coincidence. private predicate hasUpperBoundsCheck(Variable var) { exists(RelationalOperation oper, VariableAccess access | - oper.getLeftOperand() = access and + oper.getAnOperand() = access and access.getTarget() = var and // Comparing to 0 is not an upper bound check - not oper.getRightOperand().getValue() = "0" + not oper.getAnOperand().getValue() = "0" ) } @@ -171,6 +182,7 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) { node = getNodeForSource(any(Expr e)) } +cached private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Expressions computed from tainted data are also tainted exists(CallInstruction call, int argIndex | call = i2 | @@ -187,6 +199,14 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow through pointer dereference i2.(LoadInstruction).getSourceAddress() = i1 or + // Flow through partial reads of arrays and unions + i2.(LoadInstruction).getSourceValueOperand().getAnyDef() = i1 and + not i1.isResultConflated() and + ( + i1.getResultType() instanceof ArrayType or + i1.getResultType() instanceof Union + ) + or // Unary instructions tend to preserve enough information in practice that we // want taint to flow through. // The exception is `FieldAddressInstruction`. Together with the rule for @@ -195,11 +215,28 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // unrelated field. This would happen across function boundaries, where the IR // would not be able to match loads to stores. i2.(UnaryInstruction).getUnary() = i1 and - not i2 instanceof FieldAddressInstruction + ( + not i2 instanceof FieldAddressInstruction + or + i2.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union + ) or - i2.(ChiInstruction).getPartial() = i1 and + // Flow out of definition-by-reference + i2.(ChiInstruction).getPartial() = i1.(WriteSideEffectInstruction) and not i2.isResultConflated() or + // Flow from an element to an array or union that contains it. + i2.(ChiInstruction).getPartial() = i1 and + not i2.isResultConflated() and + exists(Type t | i2.getResultLanguageType().hasType(t, false) | + t instanceof Union + or + t instanceof ArrayType + or + // Buffers of unknown size + t instanceof UnknownType + ) + or exists(BinaryInstruction bin | bin = i2 and predictableInstruction(i2.getAnOperand().getDef()) and @@ -356,6 +393,16 @@ private Element adjustedSink(DataFlow::Node sink) { result.(AssignOperation).getAnOperand() = sink.asExpr() } +/** + * Holds if `tainted` may contain taint from `source`. + * + * A tainted expression is either directly user input, or is + * computed from user input in a way that users can probably + * control the exact output of the computation. + * + * This doesn't include data flow through global variables. + * If you need that you must call `taintedIncludingGlobalVars`. + */ cached predicate tainted(Expr source, Element tainted) { exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink | @@ -364,6 +411,21 @@ predicate tainted(Expr source, Element tainted) { ) } +/** + * Holds if `tainted` may contain taint from `source`, where the taint passed + * through a global variable named `globalVar`. + * + * A tainted expression is either directly user input, or is + * computed from user input in a way that users can probably + * control the exact output of the computation. + * + * This version gives the same results as tainted but also includes + * data flow through global variables. + * + * The parameter `globalVar` is the qualified name of the last global variable + * used to move the value from source to tainted. If the taint did not pass + * through a global variable, then `globalVar = ""`. + */ cached predicate taintedIncludingGlobalVars(Expr source, Element tainted, string globalVar) { tainted(source, tainted) and @@ -381,11 +443,245 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global ) } +/** + * Gets the global variable whose qualified name is `id`. Use this predicate + * together with `taintedIncludingGlobalVars`. Example: + * + * ``` + * exists(string varName | + * taintedIncludingGlobalVars(source, tainted, varName) and + * var = globalVarFromId(varName) + * ) + * ``` + */ GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() } +/** + * Resolve potential target function(s) for `call`. + * + * If `call` is a call through a function pointer (`ExprCall`) or + * targets a virtual method, simple data flow analysis is performed + * in order to identify target(s). + */ Function resolveCall(Call call) { exists(CallInstruction callInstruction | callInstruction.getAST() = call and result = Dispatch::viableCallable(callInstruction) ) } + +/** + * Provides definitions for augmenting source/sink pairs with data-flow paths + * between them. From a `@kind path-problem` query, import this module in the + * global scope, extend `TaintTrackingConfiguration`, and use `taintedWithPath` + * in place of `tainted`. + * + * Importing this module will also import the query predicates that contain the + * taint paths. + */ +module TaintedWithPath { + private newtype TSingleton = MkSingleton() + + /** + * A taint-tracking configuration that matches sources and sinks in the same + * way as the `tainted` predicate. + * + * Override `isSink` and `taintThroughGlobals` as needed, but do not provide + * a characteristic predicate. + */ + class TaintTrackingConfiguration extends TSingleton { + /** Override this to specify which elements are sinks in this configuration. */ + abstract predicate isSink(Element e); + + /** + * Override this predicate to `any()` to allow taint to flow through global + * variables. + */ + predicate taintThroughGlobals() { none() } + + /** Gets a textual representation of this element. */ + string toString() { result = "TaintTrackingConfiguration" } + } + + private class AdjustedConfiguration extends DataFlow3::Configuration { + AdjustedConfiguration() { this = "AdjustedConfiguration" } + + override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) } + + override predicate isSink(DataFlow::Node sink) { + exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink))) + } + + override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { + instructionTaintStep(n1.asInstruction(), n2.asInstruction()) + or + exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() | + writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable)) + or + readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable)) + ) + } + + override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) } + + override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) } + } + + /* + * A sink `Element` may map to multiple `DataFlowX::PathNode`s via (the + * inverse of) `adjustedSink`. For example, an `Expr` maps to all its + * conversions, and a `Variable` maps to all loads and stores from it. Because + * the path node is part of the tuple that constitutes the alert, this leads + * to duplicate alerts. + * + * To avoid showing duplicates, we edit the graph to replace the final node + * coming from the data-flow library with a node that matches exactly the + * `Element` sink that's requested. + * + * The same is done for sources. + */ + + private newtype TPathNode = + TWrapPathNode(DataFlow3::PathNode n) or + // There's a single newtype constructor for both sources and sinks since + // that makes it easiest to deal with the case where source = sink. + TEndpointPathNode(Element e) { + exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode | + cfg.hasFlow(sourceNode, sinkNode) + | + sourceNode = getNodeForSource(e) + or + e = adjustedSink(sinkNode) and + exists(TaintTrackingConfiguration ttCfg | ttCfg.isSink(e)) + ) + } + + /** An opaque type used for the nodes of a data-flow path. */ + class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * 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 + ) { + none() + } + } + + private class WrapPathNode extends PathNode, TWrapPathNode { + DataFlow3::PathNode inner() { this = TWrapPathNode(result) } + + override string toString() { result = this.inner().toString() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.inner().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + } + + private class EndpointPathNode extends PathNode, TEndpointPathNode { + Expr inner() { this = TEndpointPathNode(result) } + + override string toString() { result = this.inner().toString() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this + .inner() + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + } + + /** A PathNode whose `Element` is a source. It may also be a sink. */ + private class InitialPathNode extends EndpointPathNode { + InitialPathNode() { exists(getNodeForSource(this.inner())) } + } + + /** A PathNode whose `Element` is a sink. It may also be a source. */ + private class FinalPathNode extends EndpointPathNode { + FinalPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSink(this.inner())) } + } + + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { + DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner()) + or + // To avoid showing trivial-looking steps, we _replace_ the last node instead + // of adding an edge out of it. + exists(WrapPathNode sinkNode | + DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and + b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) + ) + or + // Same for the first node + exists(WrapPathNode sourceNode | + DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and + sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) + ) + or + // Finally, handle the case where the path goes directly from a source to a + // sink, meaning that they both need to be translated. + exists(WrapPathNode sinkNode, WrapPathNode sourceNode | + DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and + sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) and + b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) + ) + } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + key = "semmle.label" and val = n.toString() + } + + /** + * Holds if `tainted` may contain taint from `source`, where `sourceNode` and + * `sinkNode` are the corresponding `PathNode`s that can be used in a query + * to provide path explanations. Extend `TaintTrackingConfiguration` to use + * this predicate. + * + * A tainted expression is either directly user input, or is computed from + * user input in a way that users can probably control the exact output of + * the computation. + */ + predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) { + exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink | + source = sourceNode.(InitialPathNode).inner() and + flowSource = getNodeForSource(source) and + cfg.hasFlow(flowSource, flowSink) and + tainted = adjustedSink(flowSink) and + tainted = sinkNode.(FinalPathNode).inner() + ) + } + + private predicate isGlobalVariablePathNode(WrapPathNode n) { + n.inner().getNode().asVariable() instanceof GlobalOrNamespaceVariable + } + + private predicate edgesWithoutGlobals(PathNode a, PathNode b) { + edges(a, b) and + not isGlobalVariablePathNode(a) and + not isGlobalVariablePathNode(b) + } + + /** + * Holds if `tainted` can be reached from a taint source without passing + * through a global variable. + */ + predicate taintedWithoutGlobals(Element tainted) { + exists(PathNode sourceNode, FinalPathNode sinkNode | + sourceNode.(WrapPathNode).inner().getNode() = getNodeForSource(_) and + edgesWithoutGlobals+(sourceNode, sinkNode) and + tainted = sinkNode.inner() + ) + } +} 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 abb62b9a021..1dd1d9ac4cc 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 @@ -70,8 +70,7 @@ private module VirtualDispatch { // Call return exists(DataFlowCall call, ReturnKind returnKind | other = getAnOutNode(call, returnKind) and - src.(ReturnNode).getKind() = returnKind and - call.getStaticCallTarget() = src.getEnclosingCallable() + returnNodeWithKindAndEnclosingCallable(src, returnKind, call.getStaticCallTarget()) ) and allowFromArg = false or @@ -125,6 +124,18 @@ private module VirtualDispatch { } } + /** + * A ReturnNode with its ReturnKind and its enclosing callable. + * + * Used to fix a join ordering issue in flowsFrom. + */ + private predicate returnNodeWithKindAndEnclosingCallable( + ReturnNode node, ReturnKind kind, DataFlowCallable callable + ) { + node.getKind() = kind and + node.getEnclosingCallable() = callable + } + /** Call through a function pointer. */ private class DataSensitiveExprCall extends DataSensitiveCall { DataSensitiveExprCall() { not exists(this.getStaticCallTarget()) } 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..9587ea5f274 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 @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 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 @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 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 @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 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 @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..852f54974e2 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,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - 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. * * `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 any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) 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() - ) - 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()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) 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, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, 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, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) 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, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * 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). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - 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, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `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). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - 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, contentIn) 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(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ 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) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ 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 TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,8 +415,7 @@ 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 } } @@ -538,7 +423,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -678,6 +563,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 +585,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 +597,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 +611,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 +678,58 @@ 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())) + } +} + +/** + * 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(Content f) { this = TFrontHead(f) } +} + +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 } +} + +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 } +} + +/** 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 b0f2f1e24ba..97118da117c 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 @@ -36,7 +36,9 @@ class ArgumentNode extends InstructionNode { DataFlowCall getCall() { this.argumentOf(result, _) } } -private newtype TReturnKind = TNormalReturnKind() +private newtype TReturnKind = + TNormalReturnKind() or + TIndirectReturnKind(ParameterIndex index) /** * A return kind. A return kind describes how a value can be returned @@ -44,23 +46,76 @@ private newtype TReturnKind = TNormalReturnKind() */ class ReturnKind extends TReturnKind { /** Gets a textual representation of this return kind. */ - string toString() { result = "return" } + abstract string toString(); +} + +private class NormalReturnKind extends ReturnKind, TNormalReturnKind { + override string toString() { result = "return" } +} + +private class IndirectReturnKind extends ReturnKind, TIndirectReturnKind { + ParameterIndex index; + + IndirectReturnKind() { this = TIndirectReturnKind(index) } + + override string toString() { result = "outparam[" + index.toString() + "]" } } /** A data flow node that occurs as the result of a `ReturnStmt`. */ class ReturnNode extends InstructionNode { - ReturnNode() { exists(ReturnValueInstruction ret | this.getInstruction() = ret.getReturnValue()) } + Instruction primary; + + ReturnNode() { + exists(ReturnValueInstruction ret | instr = ret.getReturnValue() and primary = ret) + or + exists(ReturnIndirectionInstruction rii | + instr = rii.getSideEffectOperand().getAnyDef() and primary = rii + ) + } /** Gets the kind of this returned value. */ - ReturnKind getKind() { result = TNormalReturnKind() } + abstract ReturnKind getKind(); +} + +class ReturnValueNode extends ReturnNode { + override ReturnValueInstruction primary; + + override ReturnKind getKind() { result = TNormalReturnKind() } +} + +class ReturnIndirectionNode extends ReturnNode { + override ReturnIndirectionInstruction primary; + + override ReturnKind getKind() { result = TIndirectReturnKind(primary.getParameter().getIndex()) } } /** A data flow node that represents the output of a call. */ class OutNode extends InstructionNode { - override CallInstruction instr; + OutNode() { + instr instanceof CallInstruction or + instr instanceof WriteSideEffectInstruction + } /** Gets the underlying call. */ - DataFlowCall getCall() { result = instr } + abstract DataFlowCall getCall(); + + abstract ReturnKind getReturnKind(); +} + +private class CallOutNode extends OutNode { + override CallInstruction instr; + + override DataFlowCall getCall() { result = instr } + + override ReturnKind getReturnKind() { result instanceof NormalReturnKind } +} + +private class SideEffectOutNode extends OutNode { + override WriteSideEffectInstruction instr; + + override DataFlowCall getCall() { result = instr.getPrimaryInstruction() } + + override ReturnKind getReturnKind() { result = TIndirectReturnKind(instr.getIndex()) } } /** @@ -69,7 +124,7 @@ class OutNode extends InstructionNode { */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { result.getCall() = call and - kind = TNormalReturnKind() + result.getReturnKind() = kind } /** @@ -137,13 +192,32 @@ private class ArrayContent extends Content, TArrayContent { override Type getType() { 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() + ) +} + +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() + ) +} + /** * Holds if data can flow from `node1` to `node2` via an assignment to `f`. * Thus, `node2` references an object with a field `f` that contains the * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - none() // stub implementation + storeStepNoChi(node1, f, node2) or + storeStepChi(node1, f, node2) } /** @@ -152,7 +226,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() + ) } /** @@ -166,7 +245,7 @@ Type getErasedRepr(Type t) { } /** Gets a string representation of a type returned by `getErasedRepr`. */ -string ppReprType(Type t) { result = t.toString() } +string ppReprType(Type t) { none() } // stub implementation /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from 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 ae3a521f964..b3ab52aea47 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 @@ -63,6 +63,18 @@ 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).getInstruction().getUnconvertedResultExpression() + } + /** * DEPRECATED: See UninitializedNode. * @@ -96,6 +108,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; @@ -157,19 +172,20 @@ int getArgumentPosOfSideEffect(int index) { /** * The value of a parameter at function entry, viewed as a node in a data - * flow graph. This type includes implicit parameters. + * 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`, `InstanceParameterNode`, or + * `ExplicitParameterNode`, `ThisParameterNode`, or * `ParameterIndirectionNode`. */ class ParameterNode extends InstructionNode { ParameterNode() { // To avoid making this class abstract, we enumerate its values here - instr instanceof InitializeThisInstruction - or instr instanceof InitializeParameterInstruction or + instr instanceof InitializeThisInstruction + or instr instanceof InitializeIndirectionInstruction } @@ -178,19 +194,7 @@ class ParameterNode extends InstructionNode { * implicit `this` parameter is considered to have position `-1`, and * pointer-indirection parameters are at further negative positions. */ - predicate isParameterOf(Function f, int pos) { none() } // overridden in subclasses -} - -/** An implicit `this` parameter. */ -class InstanceParameterNode extends ParameterNode { - override InitializeThisInstruction instr; - - override predicate isParameterOf(Function f, int pos) { - pos = -1 and - instr.getEnclosingFunction() = f - } - - override string toString() { result = "this" } + predicate isParameterOf(Function f, int pos) { none() } // overridden by subclasses } /** An explicit positional parameter, not including `this` or `...`. */ @@ -204,7 +208,18 @@ class ExplicitParameterNode extends ParameterNode { /** Gets the `Parameter` associated with this node. */ Parameter getParameter() { result = instr.getParameter() } - override string toString() { result = this.getParameter().toString() } + override string toString() { result = instr.getParameter().toString() } +} + +/** An implicit `this` parameter. */ +class ThisParameterNode extends ParameterNode { + override InitializeThisInstruction instr; + + override predicate isParameterOf(Function f, int pos) { + pos = -1 and instr.getEnclosingFunction() = f + } + + override string toString() { result = "this" } } /** A virtual parameter to model the pointed-to object of a pointer parameter. */ @@ -262,6 +277,57 @@ 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 { } + +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + + ExplicitFieldStoreQualifierNode() { + not instr.isResultConflated() and + exists(StoreInstruction store, FieldInstruction field | + 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() } +} + +/** + * 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; + + ExplicitSingleFieldStoreQualifierNode() { + exists(FieldAddressInstruction field | + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) + ) + } + + override Node getPreUpdateNode() { none() } +} + /** * 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. @@ -297,6 +363,17 @@ class DefinitionByReferenceNode extends InstructionNode { Parameter getParameter() { exists(CallInstruction ci | result = ci.getStaticCallTarget().getParameter(instr.getIndex())) } + + override string toString() { + // This string should be unique enough to be helpful but common enough to + // avoid storing too many different strings. + result = + instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget().getName() + + " output argument" + or + not exists(instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget()) and + result = "output argument" + } } /** @@ -335,6 +412,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 } /** @@ -347,7 +428,7 @@ ExprNode exprNode(Expr e) { result.getExpr() = e } * Gets the `Node` corresponding to `e`, if any. Here, `e` may be a * `Conversion`. */ -ExprNode convertedExprNode(Expr e) { result.getExpr() = e } +ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e } /** * Gets the `Node` corresponding to the value of `p` at function entry. @@ -381,6 +462,16 @@ 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 @@ -424,6 +515,36 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. + // First, we add flow from write side-effects to non-conflated chi instructions through their + // partial operands. Consider the following example: + // ``` + // 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. + iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and + not iTo.isResultConflated() + or + // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). + // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. + exists(ChiInstruction chi | iFrom = chi | + not chi.isResultConflated() and + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi + ) + 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 | + type = iFrom.getResultType() and + iTo.getResultType().getSize() = size and + getFieldSizeOfClass(iTo.getResultType(), 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/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 833c929ecc5..9a75ca19154 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,7 +106,7 @@ 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) @@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType { IRNumericType() { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) + this = TIRFloatingPointType(byteSize, _, _) } } @@ -171,14 +173,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" + } } /** 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..dce1717bdc9 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 @@ -101,23 +101,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 +130,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/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll index 94d0192fe18..edf4bc00259 100644 --- 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 @@ -149,6 +149,26 @@ module InstructionSanity { count(instr.getBlock().getAPredecessor()) < 2 } + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + /** * Holds if operand `operand` consumes a value that was defined in * a different function. 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 fc9d0758125..780f636ff10 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 @@ -190,14 +190,15 @@ 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) } /** - * 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) @@ -525,7 +526,7 @@ class ReturnValueInstruction extends ReturnInstruction { final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } -class ReturnIndirectionInstruction extends Instruction { +class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -535,6 +536,12 @@ class ReturnIndirectionInstruction extends Instruction { final AddressOperand getSourceAddressOperand() { result = getAnOperand() } final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + /** + * Gets the parameter for which this instruction reads the final pointed-to value within the + * function. + */ + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } class CopyInstruction extends Instruction { 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/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/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 49cb4dd6dc4..dce1717bdc9 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 @@ -101,23 +101,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 +130,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/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll index 94d0192fe18..edf4bc00259 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll @@ -149,6 +149,26 @@ module InstructionSanity { count(instr.getBlock().getAPredecessor()) < 2 } + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + /** * Holds if operand `operand` consumes a value that was defined in * a different function. 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 fc9d0758125..780f636ff10 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 @@ -190,14 +190,15 @@ 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) } /** - * 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) @@ -525,7 +526,7 @@ class ReturnValueInstruction extends ReturnInstruction { final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } -class ReturnIndirectionInstruction extends Instruction { +class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -535,6 +536,12 @@ class ReturnIndirectionInstruction extends Instruction { final AddressOperand getSourceAddressOperand() { result = getAnOperand() } final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + /** + * Gets the parameter for which this instruction reads the final pointed-to value within the + * function. + */ + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } class CopyInstruction extends Instruction { 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/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 088cb7fa4cd..22f104e12c8 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 @@ -324,6 +324,16 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall { override predicate hasWriteSideEffect() { not expr.getTarget().(SideEffectFunction).hasOnlySpecificWriteSideEffects() } + + override Instruction getQualifierResult() { + hasQualifier() and + result = getQualifier().getResult() + } + + override predicate hasQualifier() { + exists(getQualifier()) and + not exists(MemberFunction func | expr.getTarget() = func and func.isStatic()) + } } /** 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 c3788f4c8da..ab354a3dca1 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 @@ -463,7 +467,9 @@ newtype TTranslatedElement = expr = call.getArgument(n).getFullyConverted() or expr = call.getQualifier().getFullyConverted() and - n = -1 + n = -1 and + // Exclude calls to static member functions. They don't modify the qualifier + not exists(MemberFunction func | func = call.getTarget() and func.isStatic()) ) and ( call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(n, _) and 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..1d305ce46d0 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 @@ -1100,13 +1100,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 @@ -1735,20 +1758,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 ( ( @@ -1843,13 +1866,13 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) } - 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 +1882,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 +1967,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 getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + result = super.getInstructionOperand(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()) + } } /** 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 1bfc1c8275f..67b9622c3be 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. @@ -312,7 +317,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { /** * Holds if the function has a non-`void` return type. */ - final predicate hasReturnValue() { not func.getUnspecifiedType() instanceof VoidType } + final predicate hasReturnValue() { hasReturnValue(func) } /** * Gets the single `UnmodeledDefinition` instruction for this function. @@ -454,7 +459,7 @@ abstract class TranslatedParameter extends TranslatedElement { result = getInstruction(InitializerVariableAddressTag()) or operandTag instanceof LoadOperandTag and - result = getInstruction(InitializerStoreTag()) + result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() ) or tag = InitializerIndirectStoreTag() and @@ -744,4 +749,9 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { operandTag = sideEffectOperand() and result = getUnknownType() } + + final override IRVariable getInstructionVariable(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = getIRUserVariable(getFunction(), param) + } } 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..a4c9d487437 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. */ 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..dce1717bdc9 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 @@ -101,23 +101,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 +130,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/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll index 94d0192fe18..edf4bc00259 100644 --- 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 @@ -149,6 +149,26 @@ module InstructionSanity { count(instr.getBlock().getAPredecessor()) < 2 } + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + /** * Holds if operand `operand` consumes a value that was defined in * a different function. 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 fc9d0758125..780f636ff10 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 @@ -190,14 +190,15 @@ 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) } /** - * 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) @@ -525,7 +526,7 @@ class ReturnValueInstruction extends ReturnInstruction { final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } -class ReturnIndirectionInstruction extends Instruction { +class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -535,6 +536,12 @@ class ReturnIndirectionInstruction extends Instruction { final AddressOperand getSourceAddressOperand() { result = getAnOperand() } final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + /** + * Gets the parameter for which this instruction reads the final pointed-to value within the + * function. + */ + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } class CopyInstruction extends Instruction { 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/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/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index 9e8044ede4f..d297097abd9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -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 @@ -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 @@ -438,15 +449,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 )) } 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/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index c6766983889..782800d0fa2 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -1,3 +1,9 @@ +/** + * Provides implementation classes modelling various methods of allocation + * (`malloc`, `new` etc). See `semmle.code.cpp.models.interfaces.Allocation` + * for usage information. + */ + import semmle.code.cpp.models.interfaces.Allocation /** @@ -83,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 ) ) } @@ -163,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 ) ) } @@ -249,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`. */ @@ -266,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 @@ -274,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() } } @@ -292,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()) } } @@ -312,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 d2e4951e436..2ef355bf398 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -1,4 +1,10 @@ -import semmle.code.cpp.models.interfaces.Allocation +/** + * Provides implementation classes modelling various methods of deallocation + * (`free`, `delete` etc). See `semmle.code.cpp.models.interfaces.Deallocation` + * for usage information. + */ + +import semmle.code.cpp.models.interfaces.Deallocation /** * A deallocation function such as `free`. @@ -13,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/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index aa4091fd7f2..e5e45729e0d 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,9 @@ 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() + } } 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/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/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/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/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 22e5f5ac83e..7751b47cb6c 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -118,36 +118,79 @@ 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 + ) + } +} + /** 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 +288,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 +697,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 = left / 2.pow(right) + ) } /** Only to be called by `getTruncatedUpperBounds`. */ @@ -794,6 +864,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 = left / 2.pow(right) + ) } /** 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/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll index 3a37b43b319..a24820b277f 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll @@ -328,14 +328,24 @@ GlobalOrNamespaceVariable globalVarFromId(string id) { } /** - * A variable that has any kind of upper-bound check anywhere in the program + * A variable that has any kind of upper-bound check anywhere in the program. This is + * biased towards being inclusive because there are a lot of valid ways of doing an + * upper bounds checks if we don't consider where it occurs, for example: + * ``` + * if (x < 10) { sink(x); } + * + * if (10 > y) { sink(y); } + * + * if (z > 10) { z = 10; } + * sink(z); + * ``` */ private predicate hasUpperBoundsCheck(Variable var) { exists(RelationalOperation oper, VariableAccess access | - oper.getLeftOperand() = access and + oper.getAnOperand() = access and access.getTarget() = var and // Comparing to 0 is not an upper bound check - not oper.getRightOperand().getValue() = "0" + not oper.getAnOperand().getValue() = "0" ) } diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index d6ca4ebb768..874439f4c50 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( 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..9783a92a762 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp @@ -0,0 +1,90 @@ +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 +} 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..235ec0451e7 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.ql +++ b/cpp/ql/test/library-tests/allocators/allocators.ql @@ -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/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/conditions/elements.expected b/cpp/ql/test/library-tests/conditions/elements.expected index 4e94d425a8a..1e2ca174e66 100644 --- a/cpp/ql/test/library-tests/conditions/elements.expected +++ b/cpp/ql/test/library-tests/conditions/elements.expected @@ -38,6 +38,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 +66,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 | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 19496381fba..5dde846a559 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -88,6 +88,16 @@ void test_std_move() { sink(std::move(getenv("VAR"))); } +void flow_to_outparam(char ** ret, char *arg) { + *ret = arg; +} + +void test_outparams() { + char *p2 = nullptr; + flow_to_outparam(&p2, getenv("VAR")); + sink(p2); // tainted +} + struct Point { int x; int y; diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 2b8cd83e6fe..cbcc1071902 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -101,15 +101,20 @@ | 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:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:14 | call to getenv | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | (int)... | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | access to array | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | +| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:9:113:14 | call to getenv | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:9:113:24 | (int)... | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:9:113:24 | access to array | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | | 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 | 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 3e152a00a14..1023863c460 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -15,13 +15,18 @@ | 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:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:5:103:5 | x | AST only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | 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: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:113:9:113:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:5:113:5 | x | AST only | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | IR only | +| defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | 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 | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | 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 f4bd52174f0..1e91d340250 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 @@ -31,6 +31,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..4bd0b9fdc4d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected @@ -44,7 +44,6 @@ | 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:385:8:385:10 | tmp | | test.cpp:384:11:384:13 | tmp | test.cpp:384:10:384:13 | & ... | @@ -59,7 +58,6 @@ | 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:392:8:392:10 | tmp | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:394:10:394:12 | tmp | 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 6c445fb76c1..666edf7a177 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -460,3 +460,13 @@ void throughStmtExpr(int source1, int clean1) { }); sink(local); // tainted } + +void intOutparamSource(int *p) { + *p = source(); +} + +void viaOutparam() { + int x = 0; + intOutparamSource(&x); + sink(x); // tainted [FALSE NEGATIVE] +} \ No newline at end of file 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 97a2eca5b2d..06aea8625d0 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 @@ -30,10 +30,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 | @@ -44,9 +40,6 @@ | 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 7ea30c7e4ee..26567df5831 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 @@ -40,6 +40,10 @@ | globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | 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 | @@ -62,6 +66,9 @@ | 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: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/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 1714355138c..227023fda16 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 @@ -19,6 +19,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.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index ca851dc8974..a03bd0a8cb8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -221,6 +221,15 @@ edges | 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] | @@ -504,6 +513,17 @@ nodes | 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 | @@ -580,6 +600,8 @@ nodes | 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 | 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..418ad5169c2 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -0,0 +1,134 @@ +edges +| 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 | BufferReadSideEffect [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:101:8:101:9 | BufferReadSideEffect [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:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | +| A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | +| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | +| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | BufferReadSideEffect [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 | BufferReadSideEffect [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| struct_init.c: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 | BufferReadSideEffect [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 | BufferReadSideEffect [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 | BufferReadSideEffect [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 | BufferReadSideEffect [a] | struct_init.c:14:24:14:25 | *ab [a] | +nodes +| 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 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | +| A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | +| A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | +| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | +| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| 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 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| struct_init.c: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 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [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 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +#select +| A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | 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:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| 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 | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c: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-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql new file mode 100644 index 00000000000..098c6b6bd27 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -0,0 +1,46 @@ +/** + * @kind path-problem + */ + +import semmle.code.cpp.ir.dataflow.DataFlow +import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate +import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl +import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon +import semmle.code.cpp.ir.IR +import DataFlow::PathGraph +import cpp + +class Conf extends DataFlow::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() + } +} + +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/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 6f36fa6551d..e286fda9350 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -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); +} + +struct C { + int f1; +}; + +struct C2 +{ + C f2; + + int getf2f1() { + return f2.f1; + } + + void m() { + f2.f1 = user_input(); + sink(getf2f1()); // flow + } +}; + } // namespace Simple diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql index db34eb16cb8..bc14c655159 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.getDefinedExpr(), + def.getSubBasicBlockStart() 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 72433bccfb4..524884a2d20 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -152,6 +152,16 @@ | 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: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 | +| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT | +| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | | +| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | | +| stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT | +| 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 | | 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 | | @@ -289,7 +299,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 | | @@ -299,7 +308,6 @@ | 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 | | @@ -310,7 +318,6 @@ | 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: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 | 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 54755871f6a..d92bb39d158 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp @@ -110,3 +110,24 @@ void test_stringstream_int(int source) 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 + + string path2; + path2 = user_input(); + sink(path2.c_str(), "r"); // tainted + + string path3(user_input()); + sink(path3.c_str(), "r"); // tainted +} 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 f8365ae63c7..59193d81722 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -11,6 +11,9 @@ | 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 | | 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 | 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 e3203a8d6c4..0c8d17b9cb0 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 @@ -10,6 +10,9 @@ | format.cpp:106:8:106:14 | format.cpp:105:38:105: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 | | 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 | @@ -19,12 +22,14 @@ | 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: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 | 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 4e1563cd5a6..78a15c3d9a8 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 @@ -4,6 +4,9 @@ | 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: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 | @@ -13,6 +16,7 @@ | 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: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 | diff --git a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected index ff7ee26843d..8a57ff7206e 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -11,9 +11,9 @@ | 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: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: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 | | diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index f6d9fdc8a35..a840ec593d7 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -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: @@ -4048,6 +5529,27 @@ ir.cpp: #-----| Type = [RValueReferenceType] C && # 628| [Destructor] void C::~C() # 628| params: +#-----| body: [Block] { ... } +#-----| 0: [ReturnStmt] return ... +# 628| destructions: +# 628| 0: [DestructorFieldDestruction] destructor field destruction of m_f +# 628| Type = [Struct] String +# 628| ValueCategory = prvalue +# 628| 0: [DestructorCall] call to ~String +# 628| Type = [VoidType] void +# 628| ValueCategory = prvalue +# 628| -1: [ImplicitThisFieldAccess] m_f +# 628| Type = [Struct] String +# 628| ValueCategory = lvalue +# 628| 1: [DestructorFieldDestruction] destructor field destruction of m_b +# 628| Type = [Struct] String +# 628| ValueCategory = prvalue +# 628| 0: [DestructorCall] call to ~String +# 628| Type = [VoidType] void +# 628| ValueCategory = prvalue +# 628| -1: [ImplicitThisFieldAccess] m_b +# 628| Type = [Struct] String +# 628| ValueCategory = lvalue # 630| [MemberFunction] int C::StaticMemberFunction(int) # 630| params: # 630| 0: [Parameter] x @@ -8545,6 +10047,442 @@ ir.cpp: # 1255| Type = [CharPointerType] char * # 1255| ValueCategory = prvalue(load) # 1256| 3: [ReturnStmt] return ... +# 1258| [CopyAssignmentOperator] A& A::operator=(A const&) +# 1258| params: +#-----| 0: [Parameter] p#0 +#-----| Type = [LValueReferenceType] const A & +# 1258| [MoveAssignmentOperator] A& A::operator=(A&&) +# 1258| params: +#-----| 0: [Parameter] p#0 +#-----| Type = [RValueReferenceType] A && +# 1261| [MemberFunction] void A::static_member(A*, int) +# 1261| params: +# 1261| 0: [Parameter] a +# 1261| Type = [PointerType] A * +# 1261| 1: [Parameter] x +# 1261| Type = [IntType] int +# 1261| body: [Block] { ... } +# 1262| 0: [ExprStmt] ExprStmt +# 1262| 0: [AssignExpr] ... = ... +# 1262| Type = [IntType] int +# 1262| ValueCategory = lvalue +# 1262| 0: [PointerFieldAccess] member +# 1262| Type = [IntType] int +# 1262| ValueCategory = lvalue +# 1262| -1: [VariableAccess] a +# 1262| Type = [PointerType] A * +# 1262| ValueCategory = prvalue(load) +# 1262| 1: [VariableAccess] x +# 1262| Type = [IntType] int +# 1262| ValueCategory = prvalue(load) +# 1263| 1: [ReturnStmt] return ... +# 1265| [MemberFunction] void A::static_member_without_def() +# 1265| params: +# 1268| [TopLevelFunction] A* getAnInstanceOfA() +# 1268| params: +# 1270| [TopLevelFunction] void test_static_member_functions(int, A*) +# 1270| params: +# 1270| 0: [Parameter] int_arg +# 1270| Type = [IntType] int +# 1270| 1: [Parameter] a_arg +# 1270| Type = [PointerType] A * +# 1270| body: [Block] { ... } +# 1271| 0: [DeclStmt] declaration +# 1271| 0: [VariableDeclarationEntry] definition of c +# 1271| Type = [Class] C +# 1271| init: [Initializer] initializer for c +# 1271| expr: [ConstructorCall] call to C +# 1271| Type = [VoidType] void +# 1271| ValueCategory = prvalue +# 1272| 1: [ExprStmt] ExprStmt +# 1272| 0: [FunctionCall] call to StaticMemberFunction +# 1272| Type = [IntType] int +# 1272| ValueCategory = prvalue +# 1272| -1: [VariableAccess] c +# 1272| Type = [Class] C +# 1272| ValueCategory = lvalue +# 1272| 0: [Literal] 10 +# 1272| Type = [IntType] int +# 1272| Value = [Literal] 10 +# 1272| ValueCategory = prvalue +# 1273| 2: [ExprStmt] ExprStmt +# 1273| 0: [FunctionCall] call to StaticMemberFunction +# 1273| Type = [IntType] int +# 1273| ValueCategory = prvalue +# 1273| 0: [Literal] 10 +# 1273| Type = [IntType] int +# 1273| Value = [Literal] 10 +# 1273| ValueCategory = prvalue +# 1275| 3: [DeclStmt] declaration +# 1275| 0: [VariableDeclarationEntry] definition of a +# 1275| Type = [Struct] A +# 1276| 4: [ExprStmt] ExprStmt +# 1276| 0: [FunctionCall] call to static_member +# 1276| Type = [VoidType] void +# 1276| ValueCategory = prvalue +# 1276| -1: [VariableAccess] a +# 1276| Type = [Struct] A +# 1276| ValueCategory = lvalue +# 1276| 0: [AddressOfExpr] & ... +# 1276| Type = [PointerType] A * +# 1276| ValueCategory = prvalue +# 1276| 0: [VariableAccess] a +# 1276| Type = [Struct] A +# 1276| ValueCategory = lvalue +# 1276| 1: [VariableAccess] int_arg +# 1276| Type = [IntType] int +# 1276| ValueCategory = prvalue(load) +# 1277| 5: [ExprStmt] ExprStmt +# 1277| 0: [FunctionCall] call to static_member +# 1277| Type = [VoidType] void +# 1277| ValueCategory = prvalue +# 1277| 0: [AddressOfExpr] & ... +# 1277| Type = [PointerType] A * +# 1277| ValueCategory = prvalue +# 1277| 0: [VariableAccess] a +# 1277| Type = [Struct] A +# 1277| ValueCategory = lvalue +# 1277| 1: [VariableAccess] int_arg +# 1277| Type = [IntType] int +# 1277| ValueCategory = prvalue(load) +# 1279| 6: [ExprStmt] ExprStmt +# 1279| 0: [FunctionCall] call to static_member +# 1279| Type = [VoidType] void +# 1279| ValueCategory = prvalue +# 1279| -1: [ParenthesisExpr] (...) +# 1279| Type = [PointerType] A * +# 1279| ValueCategory = prvalue +# 1279| expr: [AddressOfExpr] & ... +# 1279| Type = [PointerType] A * +# 1279| ValueCategory = prvalue +# 1279| 0: [VariableAccess] a +# 1279| Type = [Struct] A +# 1279| ValueCategory = lvalue +# 1279| 0: [VariableAccess] a_arg +# 1279| Type = [PointerType] A * +# 1279| ValueCategory = prvalue(load) +# 1279| 1: [AddExpr] ... + ... +# 1279| Type = [IntType] int +# 1279| ValueCategory = prvalue +# 1279| 0: [VariableAccess] int_arg +# 1279| Type = [IntType] int +# 1279| ValueCategory = prvalue(load) +# 1279| 1: [Literal] 2 +# 1279| Type = [IntType] int +# 1279| Value = [Literal] 2 +# 1279| ValueCategory = prvalue +# 1280| 7: [ExprStmt] ExprStmt +# 1280| 0: [FunctionCall] call to static_member +# 1280| Type = [VoidType] void +# 1280| ValueCategory = prvalue +# 1280| -1: [ParenthesisExpr] (...) +# 1280| Type = [Struct] A +# 1280| ValueCategory = lvalue +# 1280| expr: [PointerDereferenceExpr] * ... +# 1280| Type = [Struct] A +# 1280| ValueCategory = lvalue +# 1280| 0: [VariableAccess] a_arg +# 1280| Type = [PointerType] A * +# 1280| ValueCategory = prvalue(load) +# 1280| 0: [AddressOfExpr] & ... +# 1280| Type = [PointerType] A * +# 1280| ValueCategory = prvalue +# 1280| 0: [VariableAccess] a +# 1280| Type = [Struct] A +# 1280| ValueCategory = lvalue +# 1280| 1: [Literal] 99 +# 1280| Type = [IntType] int +# 1280| Value = [Literal] 99 +# 1280| ValueCategory = prvalue +# 1281| 8: [ExprStmt] ExprStmt +# 1281| 0: [FunctionCall] call to static_member +# 1281| Type = [VoidType] void +# 1281| ValueCategory = prvalue +# 1281| -1: [VariableAccess] a_arg +# 1281| Type = [PointerType] A * +# 1281| ValueCategory = prvalue(load) +# 1281| 0: [VariableAccess] a_arg +# 1281| Type = [PointerType] A * +# 1281| ValueCategory = prvalue(load) +# 1281| 1: [UnaryMinusExpr] - ... +# 1281| Type = [IntType] int +# 1281| Value = [UnaryMinusExpr] -1 +# 1281| ValueCategory = prvalue +# 1281| 0: [Literal] 1 +# 1281| Type = [IntType] int +# 1281| Value = [Literal] 1 +# 1281| ValueCategory = prvalue +# 1283| 9: [ExprStmt] ExprStmt +# 1283| 0: [FunctionCall] call to static_member_without_def +# 1283| Type = [VoidType] void +# 1283| ValueCategory = prvalue +# 1283| -1: [VariableAccess] a +# 1283| Type = [Struct] A +# 1283| ValueCategory = lvalue +# 1284| 10: [ExprStmt] ExprStmt +# 1284| 0: [FunctionCall] call to static_member_without_def +# 1284| Type = [VoidType] void +# 1284| ValueCategory = prvalue +# 1286| 11: [ExprStmt] ExprStmt +# 1286| 0: [FunctionCall] call to static_member_without_def +# 1286| Type = [VoidType] void +# 1286| ValueCategory = prvalue +# 1286| -1: [FunctionCall] call to getAnInstanceOfA +# 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) 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_sanity.expected index 735555b5a4b..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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_sanity_unsound.expected index 735555b5a4b..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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 6f6ab081347..5be14bf986c 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1249,10 +1249,70 @@ 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 { + int member; + + static void static_member(A* a, int x) { + a->member = x; + } + + static void static_member_without_def(); +}; + +A* getAnInstanceOfA(); + +void test_static_member_functions(int int_arg, A* a_arg) { + C c; + c.StaticMemberFunction(10); + C::StaticMemberFunction(10); + + A a; + a.static_member(&a, int_arg); + A::static_member(&a, int_arg); + + (&a)->static_member(a_arg, int_arg + 2); + (*a_arg).static_member(&a, 99); + a_arg->static_member(a_arg, -1); + + a.static_member_without_def(); + A::static_member_without_def(); + + 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; } // semmle-extractor-options: -std=c++17 --clang 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 28e6de0e1f1..e83fea6badc 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -69,7 +69,7 @@ bad_asts.cpp: # 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| r26_7(Point &) = Load : &:r26_5, ~mu26_4 # 26| mu26_8(unknown) = InitializeIndirection[a] : &:r26_7 # 27| r27_1(glval) = VariableAddress[b] : # 27| r27_2(glval) = VariableAddress[a] : @@ -79,7 +79,7 @@ bad_asts.cpp: # 27| r27_6(Point) = Load : &:r27_5, ~mu26_4 # 27| mu27_7(Point) = Store : &:r27_1, r27_6 # 28| v28_1(void) = NoOp : -# 26| v26_9(void) = ReturnIndirection : &:r26_7, ~mu26_4 +# 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 @@ -124,6 +124,580 @@ clang.cpp: # 5| v5_8(void) = AliasedUse : ~mu5_4 # 5| v5_9(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 : +# 1| mu1_4(unknown) = UnmodeledDefinition : +# 2| r2_1(glval<_Complex float>) = VariableAddress[cf] : +# 2| r2_2(double) = Constant[2.0] : +# 2| r2_3(_Complex float) = Convert : r2_2 +# 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_5(void) = ReturnVoid : +# 1| v1_6(void) = UnmodeledUse : mu* +# 1| v1_7(void) = AliasedUse : ~mu1_4 +# 1| v1_8(void) = ExitFunction : + +# 14| void complex_arithmetic() +# 14| Block 0 +# 14| v14_1(void) = EnterFunction : +# 14| mu14_2(unknown) = AliasedDefinition : +# 14| mu14_3(unknown) = InitializeNonLocal : +# 14| mu14_4(unknown) = UnmodeledDefinition : +# 15| r15_1(glval) = VariableAddress[f1] : +# 15| r15_2(float) = Constant[5.0] : +# 15| mu15_3(float) = Store : &:r15_1, r15_2 +# 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, ~mu14_4 +# 26| r26_3(_Complex float) = CopyValue : r26_2 +# 26| r26_4(glval<_Complex float>) = VariableAddress[cf3] : +# 26| mu26_5(_Complex float) = Store : &:r26_4, r26_3 +# 27| r27_1(glval<_Complex float>) = VariableAddress[cf1] : +# 27| r27_2(_Complex float) = Load : &:r27_1, ~mu14_4 +# 27| r27_3(_Complex float) = Negate : r27_2 +# 27| r27_4(glval<_Complex float>) = VariableAddress[cf3] : +# 27| mu27_5(_Complex float) = Store : &:r27_4, r27_3 +# 30| r30_1(glval<_Complex float>) = VariableAddress[cf1] : +# 30| r30_2(_Complex float) = Load : &:r30_1, ~mu14_4 +# 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] : +# 30| r30_4(_Complex float) = Load : &:r30_3, ~mu14_4 +# 30| r30_5(_Complex float) = Add : r30_2, r30_4 +# 30| r30_6(glval<_Complex float>) = VariableAddress[cf3] : +# 30| mu30_7(_Complex float) = Store : &:r30_6, r30_5 +# 31| r31_1(glval<_Complex float>) = VariableAddress[cf1] : +# 31| r31_2(_Complex float) = Load : &:r31_1, ~mu14_4 +# 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] : +# 31| r31_4(_Complex float) = Load : &:r31_3, ~mu14_4 +# 31| r31_5(_Complex float) = Sub : r31_2, r31_4 +# 31| r31_6(glval<_Complex float>) = VariableAddress[cf3] : +# 31| mu31_7(_Complex float) = Store : &:r31_6, r31_5 +# 32| r32_1(glval<_Complex float>) = VariableAddress[cf1] : +# 32| r32_2(_Complex float) = Load : &:r32_1, ~mu14_4 +# 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] : +# 32| r32_4(_Complex float) = Load : &:r32_3, ~mu14_4 +# 32| r32_5(_Complex float) = Mul : r32_2, r32_4 +# 32| r32_6(glval<_Complex float>) = VariableAddress[cf3] : +# 32| mu32_7(_Complex float) = Store : &:r32_6, r32_5 +# 33| r33_1(glval<_Complex float>) = VariableAddress[cf1] : +# 33| r33_2(_Complex float) = Load : &:r33_1, ~mu14_4 +# 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] : +# 33| r33_4(_Complex float) = Load : &:r33_3, ~mu14_4 +# 33| r33_5(_Complex float) = Div : r33_2, r33_4 +# 33| r33_6(glval<_Complex float>) = VariableAddress[cf3] : +# 33| mu33_7(_Complex float) = Store : &:r33_6, r33_5 +# 36| r36_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~mu14_4 +# 36| r36_3(_Imaginary float) = CopyValue : r36_2 +# 36| r36_4(glval<_Imaginary float>) = VariableAddress[jf3] : +# 36| mu36_5(_Imaginary float) = Store : &:r36_4, r36_3 +# 37| r37_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~mu14_4 +# 37| r37_3(_Imaginary float) = Negate : r37_2 +# 37| r37_4(glval<_Imaginary float>) = VariableAddress[jf3] : +# 37| mu37_5(_Imaginary float) = Store : &:r37_4, r37_3 +# 40| r40_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~mu14_4 +# 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~mu14_4 +# 40| r40_5(_Imaginary float) = Add : r40_2, r40_4 +# 40| r40_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 40| mu40_7(_Imaginary float) = Store : &:r40_6, r40_5 +# 41| r41_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~mu14_4 +# 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~mu14_4 +# 41| r41_5(_Imaginary float) = Sub : r41_2, r41_4 +# 41| r41_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 41| mu41_7(_Imaginary float) = Store : &:r41_6, r41_5 +# 42| r42_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~mu14_4 +# 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~mu14_4 +# 42| r42_5(float) = Mul : r42_2, r42_4 +# 42| r42_6(glval) = VariableAddress[f3] : +# 42| mu42_7(float) = Store : &:r42_6, r42_5 +# 43| r43_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~mu14_4 +# 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~mu14_4 +# 43| r43_5(float) = Div : r43_2, r43_4 +# 43| r43_6(glval) = VariableAddress[f3] : +# 43| mu43_7(float) = Store : &:r43_6, r43_5 +# 46| r46_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~mu14_4 +# 46| r46_3(glval) = VariableAddress[f2] : +# 46| r46_4(float) = Load : &:r46_3, ~mu14_4 +# 46| r46_5(_Complex float) = Add : r46_2, r46_4 +# 46| r46_6(glval<_Complex float>) = VariableAddress[cf3] : +# 46| mu46_7(_Complex float) = Store : &:r46_6, r46_5 +# 47| r47_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~mu14_4 +# 47| r47_3(glval) = VariableAddress[f2] : +# 47| r47_4(float) = Load : &:r47_3, ~mu14_4 +# 47| r47_5(_Complex float) = Sub : r47_2, r47_4 +# 47| r47_6(glval<_Complex float>) = VariableAddress[cf3] : +# 47| mu47_7(_Complex float) = Store : &:r47_6, r47_5 +# 48| r48_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~mu14_4 +# 48| r48_3(glval) = VariableAddress[f2] : +# 48| r48_4(float) = Load : &:r48_3, ~mu14_4 +# 48| r48_5(_Imaginary float) = Mul : r48_2, r48_4 +# 48| r48_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 48| mu48_7(_Imaginary float) = Store : &:r48_6, r48_5 +# 49| r49_1(glval<_Imaginary float>) = VariableAddress[jf1] : +# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~mu14_4 +# 49| r49_3(glval) = VariableAddress[f2] : +# 49| r49_4(float) = Load : &:r49_3, ~mu14_4 +# 49| r49_5(_Imaginary float) = Div : r49_2, r49_4 +# 49| r49_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 49| mu49_7(_Imaginary float) = Store : &:r49_6, r49_5 +# 52| r52_1(glval) = VariableAddress[f1] : +# 52| r52_2(float) = Load : &:r52_1, ~mu14_4 +# 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~mu14_4 +# 52| r52_5(_Complex float) = Add : r52_2, r52_4 +# 52| r52_6(glval<_Complex float>) = VariableAddress[cf3] : +# 52| mu52_7(_Complex float) = Store : &:r52_6, r52_5 +# 53| r53_1(glval) = VariableAddress[f1] : +# 53| r53_2(float) = Load : &:r53_1, ~mu14_4 +# 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~mu14_4 +# 53| r53_5(_Complex float) = Sub : r53_2, r53_4 +# 53| r53_6(glval<_Complex float>) = VariableAddress[cf3] : +# 53| mu53_7(_Complex float) = Store : &:r53_6, r53_5 +# 54| r54_1(glval) = VariableAddress[f1] : +# 54| r54_2(float) = Load : &:r54_1, ~mu14_4 +# 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~mu14_4 +# 54| r54_5(_Imaginary float) = Mul : r54_2, r54_4 +# 54| r54_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 54| mu54_7(_Imaginary float) = Store : &:r54_6, r54_5 +# 55| r55_1(glval) = VariableAddress[f1] : +# 55| r55_2(float) = Load : &:r55_1, ~mu14_4 +# 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] : +# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~mu14_4 +# 55| r55_5(_Imaginary float) = Div : r55_2, r55_4 +# 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] : +# 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 +# 56| v56_1(void) = NoOp : +# 14| v14_5(void) = ReturnVoid : +# 14| v14_6(void) = UnmodeledUse : mu* +# 14| v14_7(void) = AliasedUse : ~mu14_4 +# 14| v14_8(void) = ExitFunction : + +# 58| void complex_conversions() +# 58| Block 0 +# 58| v58_1(void) = EnterFunction : +# 58| mu58_2(unknown) = AliasedDefinition : +# 58| mu58_3(unknown) = InitializeNonLocal : +# 58| mu58_4(unknown) = UnmodeledDefinition : +# 59| r59_1(glval) = VariableAddress[f] : +# 59| r59_2(float) = Constant[2.0] : +# 59| mu59_3(float) = Store : &:r59_1, r59_2 +# 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, ~mu58_4 +# 70| r70_3(glval<_Complex float>) = VariableAddress[cf] : +# 70| mu70_4(_Complex float) = Store : &:r70_3, r70_2 +# 71| r71_1(glval<_Complex double>) = VariableAddress[cd] : +# 71| r71_2(_Complex double) = Load : &:r71_1, ~mu58_4 +# 71| r71_3(_Complex float) = Convert : r71_2 +# 71| r71_4(glval<_Complex float>) = VariableAddress[cf] : +# 71| mu71_5(_Complex float) = Store : &:r71_4, r71_3 +# 72| r72_1(glval<_Complex long double>) = VariableAddress[cld] : +# 72| r72_2(_Complex long double) = Load : &:r72_1, ~mu58_4 +# 72| r72_3(_Complex float) = Convert : r72_2 +# 72| r72_4(glval<_Complex float>) = VariableAddress[cf] : +# 72| mu72_5(_Complex float) = Store : &:r72_4, r72_3 +# 73| r73_1(glval<_Complex float>) = VariableAddress[cf] : +# 73| r73_2(_Complex float) = Load : &:r73_1, ~mu58_4 +# 73| r73_3(_Complex double) = Convert : r73_2 +# 73| r73_4(glval<_Complex double>) = VariableAddress[cd] : +# 73| mu73_5(_Complex double) = Store : &:r73_4, r73_3 +# 74| r74_1(glval<_Complex double>) = VariableAddress[cd] : +# 74| r74_2(_Complex double) = Load : &:r74_1, ~mu58_4 +# 74| r74_3(glval<_Complex double>) = VariableAddress[cd] : +# 74| mu74_4(_Complex double) = Store : &:r74_3, r74_2 +# 75| r75_1(glval<_Complex long double>) = VariableAddress[cld] : +# 75| r75_2(_Complex long double) = Load : &:r75_1, ~mu58_4 +# 75| r75_3(_Complex double) = Convert : r75_2 +# 75| r75_4(glval<_Complex double>) = VariableAddress[cd] : +# 75| mu75_5(_Complex double) = Store : &:r75_4, r75_3 +# 76| r76_1(glval<_Complex float>) = VariableAddress[cf] : +# 76| r76_2(_Complex float) = Load : &:r76_1, ~mu58_4 +# 76| r76_3(_Complex long double) = Convert : r76_2 +# 76| r76_4(glval<_Complex long double>) = VariableAddress[cld] : +# 76| mu76_5(_Complex long double) = Store : &:r76_4, r76_3 +# 77| r77_1(glval<_Complex double>) = VariableAddress[cd] : +# 77| r77_2(_Complex double) = Load : &:r77_1, ~mu58_4 +# 77| r77_3(_Complex long double) = Convert : r77_2 +# 77| r77_4(glval<_Complex long double>) = VariableAddress[cld] : +# 77| mu77_5(_Complex long double) = Store : &:r77_4, r77_3 +# 78| r78_1(glval<_Complex long double>) = VariableAddress[cld] : +# 78| r78_2(_Complex long double) = Load : &:r78_1, ~mu58_4 +# 78| r78_3(glval<_Complex long double>) = VariableAddress[cld] : +# 78| mu78_4(_Complex long double) = Store : &:r78_3, r78_2 +# 81| r81_1(glval) = VariableAddress[f] : +# 81| r81_2(float) = Load : &:r81_1, ~mu58_4 +# 81| r81_3(_Complex float) = Convert : r81_2 +# 81| r81_4(glval<_Complex float>) = VariableAddress[cf] : +# 81| mu81_5(_Complex float) = Store : &:r81_4, r81_3 +# 82| r82_1(glval) = VariableAddress[d] : +# 82| r82_2(double) = Load : &:r82_1, ~mu58_4 +# 82| r82_3(_Complex float) = Convert : r82_2 +# 82| r82_4(glval<_Complex float>) = VariableAddress[cf] : +# 82| mu82_5(_Complex float) = Store : &:r82_4, r82_3 +# 83| r83_1(glval) = VariableAddress[ld] : +# 83| r83_2(long double) = Load : &:r83_1, ~mu58_4 +# 83| r83_3(_Complex float) = Convert : r83_2 +# 83| r83_4(glval<_Complex float>) = VariableAddress[cf] : +# 83| mu83_5(_Complex float) = Store : &:r83_4, r83_3 +# 84| r84_1(glval) = VariableAddress[f] : +# 84| r84_2(float) = Load : &:r84_1, ~mu58_4 +# 84| r84_3(_Complex double) = Convert : r84_2 +# 84| r84_4(glval<_Complex double>) = VariableAddress[cd] : +# 84| mu84_5(_Complex double) = Store : &:r84_4, r84_3 +# 85| r85_1(glval) = VariableAddress[d] : +# 85| r85_2(double) = Load : &:r85_1, ~mu58_4 +# 85| r85_3(_Complex double) = Convert : r85_2 +# 85| r85_4(glval<_Complex double>) = VariableAddress[cd] : +# 85| mu85_5(_Complex double) = Store : &:r85_4, r85_3 +# 86| r86_1(glval) = VariableAddress[ld] : +# 86| r86_2(long double) = Load : &:r86_1, ~mu58_4 +# 86| r86_3(_Complex double) = Convert : r86_2 +# 86| r86_4(glval<_Complex double>) = VariableAddress[cd] : +# 86| mu86_5(_Complex double) = Store : &:r86_4, r86_3 +# 87| r87_1(glval) = VariableAddress[f] : +# 87| r87_2(float) = Load : &:r87_1, ~mu58_4 +# 87| r87_3(_Complex long double) = Convert : r87_2 +# 87| r87_4(glval<_Complex long double>) = VariableAddress[cld] : +# 87| mu87_5(_Complex long double) = Store : &:r87_4, r87_3 +# 88| r88_1(glval) = VariableAddress[d] : +# 88| r88_2(double) = Load : &:r88_1, ~mu58_4 +# 88| r88_3(_Complex long double) = Convert : r88_2 +# 88| r88_4(glval<_Complex long double>) = VariableAddress[cld] : +# 88| mu88_5(_Complex long double) = Store : &:r88_4, r88_3 +# 89| r89_1(glval) = VariableAddress[ld] : +# 89| r89_2(long double) = Load : &:r89_1, ~mu58_4 +# 89| r89_3(_Complex long double) = Convert : r89_2 +# 89| r89_4(glval<_Complex long double>) = VariableAddress[cld] : +# 89| mu89_5(_Complex long double) = Store : &:r89_4, r89_3 +# 92| r92_1(glval<_Complex float>) = VariableAddress[cf] : +# 92| r92_2(_Complex float) = Load : &:r92_1, ~mu58_4 +# 92| r92_3(float) = Convert : r92_2 +# 92| r92_4(glval) = VariableAddress[f] : +# 92| mu92_5(float) = Store : &:r92_4, r92_3 +# 93| r93_1(glval<_Complex double>) = VariableAddress[cd] : +# 93| r93_2(_Complex double) = Load : &:r93_1, ~mu58_4 +# 93| r93_3(float) = Convert : r93_2 +# 93| r93_4(glval) = VariableAddress[f] : +# 93| mu93_5(float) = Store : &:r93_4, r93_3 +# 94| r94_1(glval<_Complex long double>) = VariableAddress[cld] : +# 94| r94_2(_Complex long double) = Load : &:r94_1, ~mu58_4 +# 94| r94_3(float) = Convert : r94_2 +# 94| r94_4(glval) = VariableAddress[f] : +# 94| mu94_5(float) = Store : &:r94_4, r94_3 +# 95| r95_1(glval<_Complex float>) = VariableAddress[cf] : +# 95| r95_2(_Complex float) = Load : &:r95_1, ~mu58_4 +# 95| r95_3(double) = Convert : r95_2 +# 95| r95_4(glval) = VariableAddress[d] : +# 95| mu95_5(double) = Store : &:r95_4, r95_3 +# 96| r96_1(glval<_Complex double>) = VariableAddress[cd] : +# 96| r96_2(_Complex double) = Load : &:r96_1, ~mu58_4 +# 96| r96_3(double) = Convert : r96_2 +# 96| r96_4(glval) = VariableAddress[d] : +# 96| mu96_5(double) = Store : &:r96_4, r96_3 +# 97| r97_1(glval<_Complex long double>) = VariableAddress[cld] : +# 97| r97_2(_Complex long double) = Load : &:r97_1, ~mu58_4 +# 97| r97_3(double) = Convert : r97_2 +# 97| r97_4(glval) = VariableAddress[d] : +# 97| mu97_5(double) = Store : &:r97_4, r97_3 +# 98| r98_1(glval<_Complex float>) = VariableAddress[cf] : +# 98| r98_2(_Complex float) = Load : &:r98_1, ~mu58_4 +# 98| r98_3(long double) = Convert : r98_2 +# 98| r98_4(glval) = VariableAddress[ld] : +# 98| mu98_5(long double) = Store : &:r98_4, r98_3 +# 99| r99_1(glval<_Complex double>) = VariableAddress[cd] : +# 99| r99_2(_Complex double) = Load : &:r99_1, ~mu58_4 +# 99| r99_3(long double) = Convert : r99_2 +# 99| r99_4(glval) = VariableAddress[ld] : +# 99| mu99_5(long double) = Store : &:r99_4, r99_3 +# 100| r100_1(glval<_Complex long double>) = VariableAddress[cld] : +# 100| r100_2(_Complex long double) = Load : &:r100_1, ~mu58_4 +# 100| r100_3(long double) = Convert : r100_2 +# 100| r100_4(glval) = VariableAddress[ld] : +# 100| mu100_5(long double) = Store : &:r100_4, r100_3 +# 103| r103_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~mu58_4 +# 103| r103_3(_Complex float) = Convert : r103_2 +# 103| r103_4(glval<_Complex float>) = VariableAddress[cf] : +# 103| mu103_5(_Complex float) = Store : &:r103_4, r103_3 +# 104| r104_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~mu58_4 +# 104| r104_3(_Complex float) = Convert : r104_2 +# 104| r104_4(glval<_Complex float>) = VariableAddress[cf] : +# 104| mu104_5(_Complex float) = Store : &:r104_4, r104_3 +# 105| r105_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~mu58_4 +# 105| r105_3(_Complex float) = Convert : r105_2 +# 105| r105_4(glval<_Complex float>) = VariableAddress[cf] : +# 105| mu105_5(_Complex float) = Store : &:r105_4, r105_3 +# 106| r106_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~mu58_4 +# 106| r106_3(_Complex double) = Convert : r106_2 +# 106| r106_4(glval<_Complex double>) = VariableAddress[cd] : +# 106| mu106_5(_Complex double) = Store : &:r106_4, r106_3 +# 107| r107_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~mu58_4 +# 107| r107_3(_Complex double) = Convert : r107_2 +# 107| r107_4(glval<_Complex double>) = VariableAddress[cd] : +# 107| mu107_5(_Complex double) = Store : &:r107_4, r107_3 +# 108| r108_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~mu58_4 +# 108| r108_3(_Complex double) = Convert : r108_2 +# 108| r108_4(glval<_Complex double>) = VariableAddress[cd] : +# 108| mu108_5(_Complex double) = Store : &:r108_4, r108_3 +# 109| r109_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~mu58_4 +# 109| r109_3(_Complex long double) = Convert : r109_2 +# 109| r109_4(glval<_Complex long double>) = VariableAddress[cld] : +# 109| mu109_5(_Complex long double) = Store : &:r109_4, r109_3 +# 110| r110_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~mu58_4 +# 110| r110_3(_Complex long double) = Convert : r110_2 +# 110| r110_4(glval<_Complex long double>) = VariableAddress[cld] : +# 110| mu110_5(_Complex long double) = Store : &:r110_4, r110_3 +# 111| r111_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~mu58_4 +# 111| r111_3(_Complex long double) = Convert : r111_2 +# 111| r111_4(glval<_Complex long double>) = VariableAddress[cld] : +# 111| mu111_5(_Complex long double) = Store : &:r111_4, r111_3 +# 114| r114_1(glval<_Complex float>) = VariableAddress[cf] : +# 114| r114_2(_Complex float) = Load : &:r114_1, ~mu58_4 +# 114| r114_3(_Imaginary float) = Convert : r114_2 +# 114| r114_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 114| mu114_5(_Imaginary float) = Store : &:r114_4, r114_3 +# 115| r115_1(glval<_Complex double>) = VariableAddress[cd] : +# 115| r115_2(_Complex double) = Load : &:r115_1, ~mu58_4 +# 115| r115_3(_Imaginary float) = Convert : r115_2 +# 115| r115_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 115| mu115_5(_Imaginary float) = Store : &:r115_4, r115_3 +# 116| r116_1(glval<_Complex long double>) = VariableAddress[cld] : +# 116| r116_2(_Complex long double) = Load : &:r116_1, ~mu58_4 +# 116| r116_3(_Imaginary float) = Convert : r116_2 +# 116| r116_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 116| mu116_5(_Imaginary float) = Store : &:r116_4, r116_3 +# 117| r117_1(glval<_Complex float>) = VariableAddress[cf] : +# 117| r117_2(_Complex float) = Load : &:r117_1, ~mu58_4 +# 117| r117_3(_Imaginary double) = Convert : r117_2 +# 117| r117_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 117| mu117_5(_Imaginary double) = Store : &:r117_4, r117_3 +# 118| r118_1(glval<_Complex double>) = VariableAddress[cd] : +# 118| r118_2(_Complex double) = Load : &:r118_1, ~mu58_4 +# 118| r118_3(_Imaginary double) = Convert : r118_2 +# 118| r118_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 118| mu118_5(_Imaginary double) = Store : &:r118_4, r118_3 +# 119| r119_1(glval<_Complex long double>) = VariableAddress[cld] : +# 119| r119_2(_Complex long double) = Load : &:r119_1, ~mu58_4 +# 119| r119_3(_Imaginary double) = Convert : r119_2 +# 119| r119_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 119| mu119_5(_Imaginary double) = Store : &:r119_4, r119_3 +# 120| r120_1(glval<_Complex float>) = VariableAddress[cf] : +# 120| r120_2(_Complex float) = Load : &:r120_1, ~mu58_4 +# 120| r120_3(_Imaginary long double) = Convert : r120_2 +# 120| r120_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 120| mu120_5(_Imaginary long double) = Store : &:r120_4, r120_3 +# 121| r121_1(glval<_Complex double>) = VariableAddress[cd] : +# 121| r121_2(_Complex double) = Load : &:r121_1, ~mu58_4 +# 121| r121_3(_Imaginary long double) = Convert : r121_2 +# 121| r121_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 121| mu121_5(_Imaginary long double) = Store : &:r121_4, r121_3 +# 122| r122_1(glval<_Complex long double>) = VariableAddress[cld] : +# 122| r122_2(_Complex long double) = Load : &:r122_1, ~mu58_4 +# 122| r122_3(_Imaginary long double) = Convert : r122_2 +# 122| r122_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 122| mu122_5(_Imaginary long double) = Store : &:r122_4, r122_3 +# 125| r125_1(glval) = VariableAddress[f] : +# 125| r125_2(float) = Load : &:r125_1, ~mu58_4 +# 125| r125_3(_Imaginary float) = Convert : r125_2 +# 125| r125_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 125| mu125_5(_Imaginary float) = Store : &:r125_4, r125_3 +# 126| r126_1(glval) = VariableAddress[d] : +# 126| r126_2(double) = Load : &:r126_1, ~mu58_4 +# 126| r126_3(_Imaginary float) = Convert : r126_2 +# 126| r126_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 126| mu126_5(_Imaginary float) = Store : &:r126_4, r126_3 +# 127| r127_1(glval) = VariableAddress[ld] : +# 127| r127_2(long double) = Load : &:r127_1, ~mu58_4 +# 127| r127_3(_Imaginary float) = Convert : r127_2 +# 127| r127_4(glval<_Imaginary float>) = VariableAddress[jf] : +# 127| mu127_5(_Imaginary float) = Store : &:r127_4, r127_3 +# 128| r128_1(glval) = VariableAddress[f] : +# 128| r128_2(float) = Load : &:r128_1, ~mu58_4 +# 128| r128_3(_Imaginary double) = Convert : r128_2 +# 128| r128_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 128| mu128_5(_Imaginary double) = Store : &:r128_4, r128_3 +# 129| r129_1(glval) = VariableAddress[d] : +# 129| r129_2(double) = Load : &:r129_1, ~mu58_4 +# 129| r129_3(_Imaginary double) = Convert : r129_2 +# 129| r129_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 129| mu129_5(_Imaginary double) = Store : &:r129_4, r129_3 +# 130| r130_1(glval) = VariableAddress[ld] : +# 130| r130_2(long double) = Load : &:r130_1, ~mu58_4 +# 130| r130_3(_Imaginary double) = Convert : r130_2 +# 130| r130_4(glval<_Imaginary double>) = VariableAddress[jd] : +# 130| mu130_5(_Imaginary double) = Store : &:r130_4, r130_3 +# 131| r131_1(glval) = VariableAddress[f] : +# 131| r131_2(float) = Load : &:r131_1, ~mu58_4 +# 131| r131_3(_Imaginary long double) = Convert : r131_2 +# 131| r131_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 131| mu131_5(_Imaginary long double) = Store : &:r131_4, r131_3 +# 132| r132_1(glval) = VariableAddress[d] : +# 132| r132_2(double) = Load : &:r132_1, ~mu58_4 +# 132| r132_3(_Imaginary long double) = Convert : r132_2 +# 132| r132_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 132| mu132_5(_Imaginary long double) = Store : &:r132_4, r132_3 +# 133| r133_1(glval) = VariableAddress[ld] : +# 133| r133_2(long double) = Load : &:r133_1, ~mu58_4 +# 133| r133_3(_Imaginary long double) = Convert : r133_2 +# 133| r133_4(glval<_Imaginary long double>) = VariableAddress[jld] : +# 133| mu133_5(_Imaginary long double) = Store : &:r133_4, r133_3 +# 136| r136_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~mu58_4 +# 136| r136_3(float) = Convert : r136_2 +# 136| r136_4(glval) = VariableAddress[f] : +# 136| mu136_5(float) = Store : &:r136_4, r136_3 +# 137| r137_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~mu58_4 +# 137| r137_3(float) = Convert : r137_2 +# 137| r137_4(glval) = VariableAddress[f] : +# 137| mu137_5(float) = Store : &:r137_4, r137_3 +# 138| r138_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~mu58_4 +# 138| r138_3(float) = Convert : r138_2 +# 138| r138_4(glval) = VariableAddress[f] : +# 138| mu138_5(float) = Store : &:r138_4, r138_3 +# 139| r139_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~mu58_4 +# 139| r139_3(double) = Convert : r139_2 +# 139| r139_4(glval) = VariableAddress[d] : +# 139| mu139_5(double) = Store : &:r139_4, r139_3 +# 140| r140_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~mu58_4 +# 140| r140_3(double) = Convert : r140_2 +# 140| r140_4(glval) = VariableAddress[d] : +# 140| mu140_5(double) = Store : &:r140_4, r140_3 +# 141| r141_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~mu58_4 +# 141| r141_3(double) = Convert : r141_2 +# 141| r141_4(glval) = VariableAddress[d] : +# 141| mu141_5(double) = Store : &:r141_4, r141_3 +# 142| r142_1(glval<_Imaginary float>) = VariableAddress[jf] : +# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~mu58_4 +# 142| r142_3(long double) = Convert : r142_2 +# 142| r142_4(glval) = VariableAddress[ld] : +# 142| mu142_5(long double) = Store : &:r142_4, r142_3 +# 143| r143_1(glval<_Imaginary double>) = VariableAddress[jd] : +# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~mu58_4 +# 143| r143_3(long double) = Convert : r143_2 +# 143| r143_4(glval) = VariableAddress[ld] : +# 143| mu143_5(long double) = Store : &:r143_4, r143_3 +# 144| r144_1(glval<_Imaginary long double>) = VariableAddress[jld] : +# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~mu58_4 +# 144| r144_3(long double) = Convert : r144_2 +# 144| r144_4(glval) = VariableAddress[ld] : +# 144| mu144_5(long double) = Store : &:r144_4, r144_3 +# 145| v145_1(void) = NoOp : +# 58| v58_5(void) = ReturnVoid : +# 58| v58_6(void) = UnmodeledUse : mu* +# 58| v58_7(void) = AliasedUse : ~mu58_4 +# 58| v58_8(void) = ExitFunction : + ir.cpp: # 1| void Constants() # 1| Block 0 @@ -769,7 +1343,7 @@ ir.cpp: # 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| r153_7(int *) = Load : &:r153_5, ~mu153_4 # 153| mu153_8(unknown) = InitializeIndirection[p] : &:r153_7 # 153| r153_9(glval) = VariableAddress[i] : # 153| mu153_10(int) = InitializeParameter[i] : &:r153_9 @@ -836,7 +1410,7 @@ ir.cpp: # 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 : &:r153_7, ~mu153_4 +# 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 @@ -850,7 +1424,7 @@ ir.cpp: # 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| r171_7(int *) = Load : &:r171_5, ~mu171_4 # 171| mu171_8(unknown) = InitializeIndirection[p] : &:r171_7 # 171| r171_9(glval) = VariableAddress[i] : # 171| mu171_10(int) = InitializeParameter[i] : &:r171_9 @@ -923,7 +1497,7 @@ ir.cpp: # 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 : &:r171_7, ~mu171_4 +# 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 @@ -972,11 +1546,11 @@ ir.cpp: # 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| r193_7(int *) = Load : &:r193_5, ~mu193_4 # 193| mu193_8(unknown) = InitializeIndirection[p] : &:r193_7 # 193| r193_9(glval) = VariableAddress[q] : # 193| mu193_10(int *) = InitializeParameter[q] : &:r193_9 -# 193| r193_11(int *) = Load : &:r193_9, ~mu193_10 +# 193| r193_11(int *) = Load : &:r193_9, ~mu193_4 # 193| mu193_12(unknown) = InitializeIndirection[q] : &:r193_11 # 194| r194_1(glval) = VariableAddress[b] : # 194| mu194_2(bool) = Uninitialized[b] : &:r194_1 @@ -1023,8 +1597,8 @@ ir.cpp: # 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 : &:r193_7, ~mu193_4 -# 193| v193_14(void) = ReturnIndirection : &:r193_11, ~mu193_4 +# 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 @@ -1038,7 +1612,7 @@ ir.cpp: # 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| r204_7(int *) = Load : &:r204_5, ~mu204_4 # 204| mu204_8(unknown) = InitializeIndirection[p] : &:r204_7 # 205| r205_1(glval) = VariableAddress[q] : # 205| mu205_2(int *) = Uninitialized[q] : &:r205_1 @@ -1073,7 +1647,7 @@ 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 : &:r204_7, ~mu204_4 +# 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 @@ -1672,7 +2246,7 @@ ir.cpp: # 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| r341_7(int *) = Load : &:r341_5, ~mu341_4 # 341| mu341_8(unknown) = InitializeIndirection[p] : &:r341_7 # 342| r342_1(int) = Constant[1] : # 342| r342_2(glval) = VariableAddress[p] : @@ -1684,7 +2258,7 @@ ir.cpp: # 343| r343_3(int *) = Load : &:r343_2, ~mu341_4 # 343| r343_4(int) = Load : &:r343_3, ~mu341_4 # 343| mu343_5(int) = Store : &:r343_1, r343_4 -# 341| v341_9(void) = ReturnIndirection : &:r341_7, ~mu341_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* @@ -2951,11 +3525,11 @@ ir.cpp: # 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| r622_7(String &) = Load : &:r622_5, ~mu622_4 # 622| mu622_8(unknown) = InitializeIndirection[r] : &:r622_7 # 622| r622_9(glval) = VariableAddress[p] : # 622| mu622_10(String *) = InitializeParameter[p] : &:r622_9 -# 622| r622_11(String *) = Load : &:r622_9, ~mu622_10 +# 622| r622_11(String *) = Load : &:r622_9, ~mu622_4 # 622| mu622_12(unknown) = InitializeIndirection[p] : &:r622_11 # 622| r622_13(glval) = VariableAddress[s] : # 622| mu622_14(String) = InitializeParameter[s] : &:r622_13 @@ -2984,13 +3558,34 @@ ir.cpp: # 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~mu622_4 # 625| mu625_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r625_2 # 626| v626_1(void) = NoOp : -# 622| v622_15(void) = ReturnIndirection : &:r622_7, ~mu622_4 -# 622| v622_16(void) = ReturnIndirection : &:r622_11, ~mu622_4 +# 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 : +# 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 : + # 630| int C::StaticMemberFunction(int) # 630| Block 0 # 630| v630_1(void) = EnterFunction : @@ -3170,14 +3765,14 @@ ir.cpp: # 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| r675_7(int &) = Load : &:r675_5, ~mu675_4 # 675| mu675_8(unknown) = InitializeIndirection[r] : &:r675_7 # 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| mu676_5(int) = Store : &:r676_1, r676_4 -# 675| v675_9(void) = ReturnIndirection : &:r675_7, ~mu675_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* @@ -3363,14 +3958,14 @@ ir.cpp: # 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| r715_7(void *) = Load : &:r715_5, ~mu715_4 # 715| mu715_8(unknown) = InitializeIndirection[x] : &:r715_7 # 715| r715_9(glval) = VariableAddress[y] : # 715| mu715_10(char) = InitializeParameter[y] : &:r715_9 # 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 : &:r715_7, ~mu715_4 +# 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* @@ -3487,7 +4082,7 @@ 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, ~mu724_4 # 735| mu735_5(unknown) = InitializeIndirection[s] : &:r735_4 # 736| r736_1(glval) = VariableAddress[#throw736:5] : # 736| mu736_2(String) = Uninitialized[#throw736:5] : &:r736_1 @@ -3510,7 +4105,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, ~mu724_4 # 738| mu738_5(unknown) = InitializeIndirection[e] : &:r738_4 # 738| v738_6(void) = NoOp : #-----| Goto -> Block 14 @@ -3534,7 +4129,7 @@ ir.cpp: # 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 +#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Base *) = CopyValue : r745_5 #-----| r0_6(glval) = FieldAddress[base_s] : r0_5 @@ -3557,7 +4152,7 @@ ir.cpp: #-----| r0_20(glval) = CopyValue : r0_19 #-----| r0_21(Base &) = CopyValue : r0_20 #-----| mu0_22(Base &) = Store : &:r0_18, r0_21 -#-----| v0_23(void) = ReturnIndirection : &:r0_3, ~mu745_4 +#-----| 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* @@ -3573,7 +4168,7 @@ ir.cpp: # 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 +#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 # 745| r745_6(glval) = FieldAddress[base_s] : r745_5 # 745| r745_7(glval) = FunctionAddress[String] : @@ -3581,7 +4176,7 @@ ir.cpp: # 745| mu745_9(unknown) = ^CallSideEffect : ~mu745_4 # 745| mu745_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_6 # 745| v745_11(void) = NoOp : -#-----| v0_5(void) = ReturnIndirection : &:r0_3, ~mu745_4 +#-----| 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 @@ -3631,7 +4226,7 @@ ir.cpp: # 754| r754_5(glval) = InitializeThis : #-----| 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, ~mu754_4 #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Middle *) = CopyValue : r754_5 #-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 @@ -3671,7 +4266,7 @@ ir.cpp: #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Middle &) = CopyValue : r0_34 #-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection : &:r0_3, ~mu754_4 +#-----| 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* @@ -3731,7 +4326,7 @@ ir.cpp: # 763| r763_5(glval) = InitializeThis : #-----| 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, ~mu763_4 #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Derived *) = CopyValue : r763_5 #-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 @@ -3771,7 +4366,7 @@ ir.cpp: #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Derived &) = CopyValue : r0_34 #-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection : &:r0_3, ~mu763_4 +#-----| 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* @@ -4462,7 +5057,7 @@ ir.cpp: # 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| r883_9(void *) = Load : &:r883_7, ~mu883_4 # 883| mu883_10(unknown) = InitializeIndirection[p] : &:r883_9 # 884| r884_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 884| r884_2(..(*)(..)) = Load : &:r884_1, ~mu883_4 @@ -4475,7 +5070,7 @@ ir.cpp: # 885| r885_4(glval<..(*)(..)>) = VariableAddress[pfn] : # 885| mu885_5(..(*)(..)) = Store : &:r885_4, r885_3 # 886| v886_1(void) = NoOp : -# 883| v883_11(void) = ReturnIndirection : &:r883_9, ~mu883_4 +# 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 @@ -4491,7 +5086,7 @@ ir.cpp: # 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| r888_9(__va_list_tag *) = Load : &:r888_7, ~mu888_4 # 888| mu888_10(unknown) = InitializeIndirection[args] : &:r888_9 # 889| r889_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 889| mu889_2(__va_list_tag[1]) = Uninitialized[args2] : &:r889_1 @@ -4524,7 +5119,7 @@ ir.cpp: # 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 : &:r888_9, ~mu888_4 +# 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 @@ -4540,7 +5135,7 @@ ir.cpp: # 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| r896_9(unknown[11]) = Load : &:r896_7, ~mu896_4 # 896| mu896_10(unknown) = InitializeIndirection[#ellipsis] : &:r896_9 # 897| r897_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 897| mu897_2(__va_list_tag[1]) = Uninitialized[args] : &:r897_1 @@ -5027,7 +5622,7 @@ ir.cpp: # 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| r996_7(int *) = Load : &:r996_5, ~mu996_4 # 996| mu996_8(unknown) = InitializeIndirection[a] : &:r996_7 # 996| r996_9(glval<..(*)(..)>) = VariableAddress[fn] : # 996| mu996_10(..(*)(..)) = InitializeParameter[fn] : &:r996_9 @@ -5044,7 +5639,7 @@ ir.cpp: # 997| mu997_11(unknown) = ^CallSideEffect : ~mu996_4 # 997| r997_12(int) = Add : r997_6, r997_10 # 997| mu997_13(int) = Store : &:r997_1, r997_12 -# 996| v996_11(void) = ReturnIndirection : &:r996_7, ~mu996_4 +# 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* @@ -5201,7 +5796,7 @@ ir.cpp: # 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| r1040_9(String &) = Load : &:r1040_7, ~mu1040_4 # 1040| mu1040_10(unknown) = InitializeIndirection[s] : &:r1040_9 # 1041| r1041_1(glval) = VariableAddress[lambda_empty] : # 1041| r1041_2(glval) = VariableAddress[#temp1041:23] : @@ -5354,7 +5949,7 @@ ir.cpp: # 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~mu1040_4 # 1055| mu1055_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1055_2 # 1056| v1056_1(void) = NoOp : -# 1040| v1040_11(void) = ReturnIndirection : &:r1040_9, ~mu1040_4 +# 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 @@ -5624,7 +6219,7 @@ ir.cpp: # 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| r1077_7(vector &) = Load : &:r1077_5, ~mu1077_4 # 1077| mu1077_8(unknown) = InitializeIndirection[v] : &:r1077_7 # 1078| r1078_1(glval &>) = VariableAddress[(__range)] : # 1078| r1078_2(glval &>) = VariableAddress[v] : @@ -5705,13 +6300,13 @@ ir.cpp: #-----| Goto -> Block 5 # 1088| Block 5 -# 1088| v1088_1(void) = NoOp : -# 1089| v1089_1(void) = NoOp : -# 1077| v1077_9(void) = ReturnIndirection : &: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 : +# 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 : #-----| Block 6 #-----| r0_24(glval) = VariableAddress[(__begin)] : @@ -5817,13 +6412,13 @@ ir.cpp: # 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| r1113_7(unsigned int &) = Load : &:r1113_5, ~mu1113_4 # 1113| mu1113_8(unknown) = InitializeIndirection[a] : &:r1113_7 # 1113| r1113_9(glval) = VariableAddress[b] : # 1113| mu1113_10(unsigned int) = InitializeParameter[b] : &:r1113_9 # 1113| r1113_11(glval) = VariableAddress[c] : # 1113| mu1113_12(unsigned int &) = InitializeParameter[c] : &:r1113_11 -# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_12 +# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_4 # 1113| mu1113_14(unknown) = InitializeIndirection[c] : &:r1113_13 # 1113| r1113_15(glval) = VariableAddress[d] : # 1113| mu1113_16(unsigned int) = InitializeParameter[d] : &:r1113_15 @@ -5838,8 +6433,8 @@ ir.cpp: # 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 # 1120| v1120_1(void) = NoOp : -# 1113| v1113_17(void) = ReturnIndirection : &:r1113_7, ~mu1113_4 -# 1113| v1113_18(void) = ReturnIndirection : &:r1113_13, ~mu1113_4 +# 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 @@ -5987,7 +6582,7 @@ 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, ~mu1142_4 # 1153| mu1153_5(unknown) = InitializeIndirection[s] : &:r1153_4 # 1154| r1154_1(glval) = VariableAddress[#throw1154:5] : # 1154| mu1154_2(String) = Uninitialized[#throw1154:5] : &:r1154_1 @@ -6010,7 +6605,7 @@ 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, ~mu1142_4 # 1156| mu1156_5(unknown) = InitializeIndirection[e] : &:r1156_4 # 1156| v1156_6(void) = NoOp : #-----| Goto -> Block 13 @@ -6364,7 +6959,7 @@ ir.cpp: # 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| r1240_7(char *) = Load : &:r1240_5, ~mu1240_4 # 1240| mu1240_8(unknown) = InitializeIndirection[dynamic] : &:r1240_7 # 1241| r1241_1(glval) = VariableAddress[a#init] : # 1241| r1241_2(bool) = Load : &:r1241_1, ~mu1240_4 @@ -6415,12 +7010,12 @@ ir.cpp: #-----| Goto -> Block 5 # 1244| Block 5 -# 1244| v1244_1(void) = NoOp : -# 1240| v1240_9(void) = ReturnIndirection : &: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 : +# 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 : # 1241| Block 6 # 1241| r1241_4(glval) = VariableAddress[a] : @@ -6440,11 +7035,11 @@ ir.cpp: # 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| r1251_7(char *) = Load : &:r1251_5, ~mu1251_4 # 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7 # 1251| r1251_9(glval) = VariableAddress[s2] : # 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9 -# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_10 +# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_4 # 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11 # 1252| r1252_1(glval) = VariableAddress[buffer] : # 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1 @@ -6476,13 +7071,476 @@ ir.cpp: # 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~mu1251_4 # 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3 # 1256| v1256_1(void) = NoOp : -# 1251| v1251_13(void) = ReturnIndirection : &:r1251_7, ~mu1251_4 -# 1251| v1251_14(void) = ReturnIndirection : &:r1251_11, ~mu1251_4 +# 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 : +# 1261| void A::static_member(A*, int) +# 1261| Block 0 +# 1261| v1261_1(void) = EnterFunction : +# 1261| mu1261_2(unknown) = AliasedDefinition : +# 1261| mu1261_3(unknown) = InitializeNonLocal : +# 1261| mu1261_4(unknown) = UnmodeledDefinition : +# 1261| r1261_5(glval) = VariableAddress[a] : +# 1261| mu1261_6(A *) = InitializeParameter[a] : &:r1261_5 +# 1261| r1261_7(A *) = Load : &:r1261_5, ~mu1261_4 +# 1261| mu1261_8(unknown) = InitializeIndirection[a] : &:r1261_7 +# 1261| r1261_9(glval) = VariableAddress[x] : +# 1261| mu1261_10(int) = InitializeParameter[x] : &:r1261_9 +# 1262| r1262_1(glval) = VariableAddress[x] : +# 1262| r1262_2(int) = Load : &:r1262_1, ~mu1261_4 +# 1262| r1262_3(glval) = VariableAddress[a] : +# 1262| r1262_4(A *) = Load : &:r1262_3, ~mu1261_4 +# 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 : + +# 1270| void test_static_member_functions(int, A*) +# 1270| Block 0 +# 1270| v1270_1(void) = EnterFunction : +# 1270| mu1270_2(unknown) = AliasedDefinition : +# 1270| mu1270_3(unknown) = InitializeNonLocal : +# 1270| mu1270_4(unknown) = UnmodeledDefinition : +# 1270| r1270_5(glval) = VariableAddress[int_arg] : +# 1270| mu1270_6(int) = InitializeParameter[int_arg] : &:r1270_5 +# 1270| r1270_7(glval) = VariableAddress[a_arg] : +# 1270| mu1270_8(A *) = InitializeParameter[a_arg] : &:r1270_7 +# 1270| r1270_9(A *) = Load : &:r1270_7, ~mu1270_4 +# 1270| mu1270_10(unknown) = InitializeIndirection[a_arg] : &:r1270_9 +# 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_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 +# 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 +# 1275| r1275_1(glval) = VariableAddress[a] : +# 1275| mu1275_2(A) = Uninitialized[a] : &:r1275_1 +# 1276| r1276_1(glval) = VariableAddress[a] : +# 1276| r1276_2(glval) = FunctionAddress[static_member] : +# 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| 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_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| 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_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_6(glval) = VariableAddress[int_arg] : +# 1279| r1279_7(int) = Load : &:r1279_6, ~mu1270_4 +# 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_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r1279_5 +# 1280| r1280_1(glval) = VariableAddress[a_arg] : +# 1280| r1280_2(A *) = Load : &:r1280_1, ~mu1270_4 +# 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_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r1280_6 +# 1281| r1281_1(glval) = VariableAddress[a_arg] : +# 1281| r1281_2(A *) = Load : &:r1281_1, ~mu1270_4 +# 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_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_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 +# 1284| r1284_1(glval) = FunctionAddress[static_member_without_def] : +# 1284| v1284_2(void) = Call : func:r1284_1 +# 1284| mu1284_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| r1286_1(glval) = FunctionAddress[getAnInstanceOfA] : +# 1286| r1286_2(A *) = Call : func:r1286_1 +# 1286| mu1286_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| r1286_4(glval) = FunctionAddress[static_member_without_def] : +# 1286| v1286_5(void) = Call : func:r1286_4 +# 1286| mu1286_6(unknown) = ^CallSideEffect : ~mu1270_4 +# 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 : + +# 1289| int missingReturnValue(bool, int) +# 1289| Block 0 +# 1289| v1289_1(void) = EnterFunction : +# 1289| mu1289_2(unknown) = AliasedDefinition : +# 1289| mu1289_3(unknown) = InitializeNonLocal : +# 1289| mu1289_4(unknown) = UnmodeledDefinition : +# 1289| r1289_5(glval) = VariableAddress[b] : +# 1289| mu1289_6(bool) = InitializeParameter[b] : &:r1289_5 +# 1289| r1289_7(glval) = VariableAddress[x] : +# 1289| mu1289_8(int) = InitializeParameter[x] : &:r1289_7 +# 1290| r1290_1(glval) = VariableAddress[b] : +# 1290| r1290_2(bool) = Load : &:r1290_1, ~mu1289_4 +# 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, ~mu1289_4 +# 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 +# 1289| r1289_9(glval) = VariableAddress[#return] : +# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~mu1289_4 +# 1289| v1289_11(void) = UnmodeledUse : mu* +# 1289| v1289_12(void) = AliasedUse : ~mu1289_4 +# 1289| v1289_13(void) = ExitFunction : + +# 1295| void returnVoid(int, int) +# 1295| Block 0 +# 1295| v1295_1(void) = EnterFunction : +# 1295| mu1295_2(unknown) = AliasedDefinition : +# 1295| mu1295_3(unknown) = InitializeNonLocal : +# 1295| mu1295_4(unknown) = UnmodeledDefinition : +# 1295| r1295_5(glval) = VariableAddress[x] : +# 1295| mu1295_6(int) = InitializeParameter[x] : &:r1295_5 +# 1295| r1295_7(glval) = VariableAddress[y] : +# 1295| mu1295_8(int) = InitializeParameter[y] : &:r1295_7 +# 1296| r1296_1(glval) = FunctionAddress[IntegerOps] : +# 1296| r1296_2(glval) = VariableAddress[x] : +# 1296| r1296_3(int) = Load : &:r1296_2, ~mu1295_4 +# 1296| r1296_4(glval) = VariableAddress[y] : +# 1296| r1296_5(int) = Load : &:r1296_4, ~mu1295_4 +# 1296| v1296_6(void) = Call : func:r1296_1, 0:r1296_3, 1:r1296_5 +# 1296| mu1296_7(unknown) = ^CallSideEffect : ~mu1295_4 +# 1296| v1296_8(void) = NoOp : +# 1295| v1295_9(void) = ReturnVoid : +# 1295| v1295_10(void) = UnmodeledUse : mu* +# 1295| v1295_11(void) = AliasedUse : ~mu1295_4 +# 1295| v1295_12(void) = ExitFunction : + +# 1299| void gccBinaryConditional(bool, int, long) +# 1299| Block 0 +# 1299| v1299_1(void) = EnterFunction : +# 1299| mu1299_2(unknown) = AliasedDefinition : +# 1299| mu1299_3(unknown) = InitializeNonLocal : +# 1299| mu1299_4(unknown) = UnmodeledDefinition : +# 1299| r1299_5(glval) = VariableAddress[b] : +# 1299| mu1299_6(bool) = InitializeParameter[b] : &:r1299_5 +# 1299| r1299_7(glval) = VariableAddress[x] : +# 1299| mu1299_8(int) = InitializeParameter[x] : &:r1299_7 +# 1299| r1299_9(glval) = VariableAddress[y] : +# 1299| mu1299_10(long) = InitializeParameter[y] : &:r1299_9 +# 1300| r1300_1(glval) = VariableAddress[z] : +# 1300| r1300_2(glval) = VariableAddress[x] : +# 1300| r1300_3(int) = Load : &:r1300_2, ~mu1299_4 +# 1300| mu1300_4(int) = Store : &:r1300_1, r1300_3 +# 1301| r1301_1(glval) = VariableAddress[b] : +# 1301| r1301_2(bool) = Load : &:r1301_1, ~mu1299_4 +# 1301| v1301_3(void) = ConditionalBranch : r1301_2 +#-----| False -> Block 3 +#-----| True -> Block 2 + +# 1301| Block 1 +# 1301| r1301_4(glval) = VariableAddress[#temp1301:9] : +# 1301| r1301_5(int) = Load : &:r1301_4, ~mu1299_4 +# 1301| r1301_6(glval) = VariableAddress[z] : +# 1301| mu1301_7(int) = Store : &:r1301_6, r1301_5 +# 1302| r1302_1(glval) = VariableAddress[b] : +# 1302| r1302_2(bool) = Load : &:r1302_1, ~mu1299_4 +# 1302| 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, ~mu1299_4 +# 1301| r1301_12(glval) = VariableAddress[#temp1301:9] : +# 1301| mu1301_13(int) = Store : &:r1301_12, r1301_11 +#-----| Goto -> Block 1 + +# 1302| Block 4 +# 1302| r1302_4(glval) = VariableAddress[#temp1302:9] : +# 1302| r1302_5(long) = Load : &:r1302_4, ~mu1299_4 +# 1302| r1302_6(int) = Convert : r1302_5 +# 1302| r1302_7(glval) = VariableAddress[z] : +# 1302| mu1302_8(int) = Store : &:r1302_7, r1302_6 +# 1303| r1303_1(glval) = VariableAddress[x] : +# 1303| r1303_2(int) = Load : &:r1303_1, ~mu1299_4 +# 1303| r1303_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, ~mu1299_4 +# 1302| r1302_13(glval) = VariableAddress[#temp1302:9] : +# 1302| mu1302_14(long) = Store : &:r1302_13, r1302_12 +#-----| Goto -> Block 4 + +# 1303| Block 7 +# 1303| r1303_6(glval) = VariableAddress[#temp1303:9] : +# 1303| r1303_7(int) = Load : &:r1303_6, ~mu1299_4 +# 1303| r1303_8(glval) = VariableAddress[z] : +# 1303| mu1303_9(int) = Store : &:r1303_8, r1303_7 +# 1304| r1304_1(glval) = VariableAddress[x] : +# 1304| r1304_2(int) = Load : &:r1304_1, ~mu1299_4 +# 1304| r1304_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, ~mu1299_4 +# 1303| r1303_14(glval) = VariableAddress[#temp1303:9] : +# 1303| mu1303_15(int) = Store : &:r1303_14, r1303_13 +#-----| Goto -> Block 7 + +# 1304| Block 10 +# 1304| r1304_6(glval) = VariableAddress[#temp1304:9] : +# 1304| r1304_7(long) = Load : &:r1304_6, ~mu1299_4 +# 1304| r1304_8(int) = Convert : r1304_7 +# 1304| r1304_9(glval) = VariableAddress[z] : +# 1304| mu1304_10(int) = Store : &:r1304_9, r1304_8 +# 1305| r1305_1(glval) = VariableAddress[y] : +# 1305| r1305_2(long) = Load : &:r1305_1, ~mu1299_4 +# 1305| r1305_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, ~mu1299_4 +# 1304| r1304_15(glval) = VariableAddress[#temp1304:9] : +# 1304| mu1304_16(long) = Store : &:r1304_15, r1304_14 +#-----| Goto -> Block 10 + +# 1305| Block 13 +# 1305| r1305_6(glval) = VariableAddress[#temp1305:9] : +# 1305| r1305_7(long) = Load : &:r1305_6, ~mu1299_4 +# 1305| r1305_8(int) = Convert : r1305_7 +# 1305| r1305_9(glval) = VariableAddress[z] : +# 1305| mu1305_10(int) = Store : &:r1305_9, r1305_8 +# 1306| r1306_1(glval) = VariableAddress[y] : +# 1306| r1306_2(long) = Load : &:r1306_1, ~mu1299_4 +# 1306| r1306_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, ~mu1299_4 +# 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, ~mu1299_4 +# 1306| r1306_8(int) = Convert : r1306_7 +# 1306| r1306_9(glval) = VariableAddress[z] : +# 1306| mu1306_10(int) = Store : &:r1306_9, r1306_8 +# 1308| r1308_1(glval) = VariableAddress[x] : +# 1308| r1308_2(int) = Load : &:r1308_1, ~mu1299_4 +# 1308| r1308_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, ~mu1299_4 +# 1306| r1306_15(glval) = VariableAddress[#temp1306:9] : +# 1306| mu1306_16(long) = Store : &:r1306_15, r1306_14 +#-----| Goto -> Block 16 + +# 1308| Block 19 +# 1308| r1308_6(glval) = VariableAddress[#temp1308:9] : +# 1308| r1308_7(int) = Load : &:r1308_6, ~mu1299_4 +# 1308| r1308_8(glval) = VariableAddress[z] : +# 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 +# 1309| v1309_1(void) = NoOp : +# 1299| v1299_11(void) = ReturnVoid : +# 1299| v1299_12(void) = UnmodeledUse : mu* +# 1299| v1299_13(void) = AliasedUse : ~mu1299_4 +# 1299| v1299_14(void) = ExitFunction : + +# 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, ~mu1299_4 +# 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, ~mu1299_4 +# 1308| v1308_23(void) = ConditionalBranch : r1308_22 +#-----| False -> Block 25 +#-----| True -> Block 23 + +# 1308| Block 25 +# 1308| r1308_24(glval) = VariableAddress[y] : +# 1308| r1308_25(long) = Load : &:r1308_24, ~mu1299_4 +# 1308| r1308_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, ~mu1299_4 +# 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| mu1314_4(unknown) = UnmodeledDefinition : +# 1314| r1314_5(glval) = VariableAddress[x] : +# 1314| mu1314_6(int) = InitializeParameter[x] : &:r1314_5 +# 1314| r1314_7(glval) = VariableAddress[y] : +# 1314| mu1314_8(int) = InitializeParameter[y] : &:r1314_7 +# 1315| r1315_1(glval) = VariableAddress[#return] : +# 1315| r1315_2(glval) = FunctionAddress[predicateA] : +# 1315| r1315_3(bool) = Call : func:r1315_2 +# 1315| mu1315_4(unknown) = ^CallSideEffect : ~mu1314_4 +# 1315| 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 : ~mu1314_4 +# 1315| v1315_9(void) = ConditionalBranch : r1315_7 +#-----| False -> Block 3 +#-----| True -> Block 2 + +# 1315| Block 2 +# 1315| r1315_10(glval) = VariableAddress[x] : +# 1315| r1315_11(int) = Load : &:r1315_10, ~mu1314_4 +# 1315| r1315_12(glval) = VariableAddress[#temp1315:12] : +# 1315| mu1315_13(int) = Store : &:r1315_12, r1315_11 +#-----| Goto -> Block 4 + +# 1315| Block 3 +# 1315| r1315_14(glval) = VariableAddress[y] : +# 1315| r1315_15(int) = Load : &:r1315_14, ~mu1314_4 +# 1315| r1315_16(glval) = VariableAddress[#temp1315:12] : +# 1315| mu1315_17(int) = Store : &:r1315_16, r1315_15 +#-----| Goto -> Block 4 + +# 1315| Block 4 +# 1315| r1315_18(glval) = VariableAddress[#temp1315:12] : +# 1315| r1315_19(int) = Load : &:r1315_18, ~mu1314_4 +# 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 +# 1314| r1314_9(glval) = VariableAddress[#return] : +# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~mu1314_4 +# 1314| v1314_11(void) = UnmodeledUse : mu* +# 1314| v1314_12(void) = AliasedUse : ~mu1314_4 +# 1314| v1314_13(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 @@ -6538,14 +7596,14 @@ struct_init.cpp: # 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| r16_7(Info *) = Load : &:r16_5, ~mu16_4 # 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7 # 17| r17_1(glval) = VariableAddress[info] : # 17| r17_2(Info *) = Load : &:r17_1, ~mu16_4 # 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 : &:r16_7, ~mu16_4 +# 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 @@ -6618,7 +7676,7 @@ struct_init.cpp: # 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| r36_7(char *) = Load : &:r36_5, ~mu36_4 # 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7 # 37| r37_1(glval) = VariableAddress[static_infos#init] : # 37| r37_2(bool) = Load : &:r37_1, ~mu36_4 @@ -6635,7 +7693,7 @@ struct_init.cpp: # 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~mu36_4 # 41| mu41_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r41_3 # 42| v42_1(void) = NoOp : -# 36| v36_9(void) = ReturnIndirection : &:r36_7, ~mu36_4 +# 36| v36_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 diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index 735555b5a4b..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index 735555b5a4b..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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 index 735555b5a4b..3a1a30265b2 100644 --- 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 @@ -13,6 +13,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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 2f69b579c30..8fdffc0569a 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 @@ -89,7 +89,7 @@ ssa.cpp: # 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 : &:r13_8, m28_3 +# 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* @@ -257,12 +257,12 @@ ssa.cpp: #-----| Goto (back edge) -> Block 1 # 71| Block 3 -# 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection : &: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 : +# 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 : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -806,7 +806,7 @@ ssa.cpp: # 181| r181_3(int *) = Load : &:r181_2, m179_7 # 181| r181_4(int) = Load : &:r181_3, ~m179_9 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection : &:r179_8, m179_9 +# 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* @@ -853,10 +853,10 @@ ssa.cpp: # 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 # 192| v192_1(void) = NoOp : -# 184| v184_24(void) = ReturnIndirection : &:r184_8, ~m186_2 -# 184| v184_25(void) = ReturnIndirection : &:r184_13, ~m186_2 -# 184| v184_26(void) = ReturnIndirection : &:r184_18, m184_19 -# 184| v184_27(void) = ReturnIndirection : &:r184_22, m184_23 +# 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 @@ -913,8 +913,8 @@ 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 : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection : &:r198_12, m198_13 +# 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* @@ -1189,7 +1189,7 @@ 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 : &:r247_8, ~m250_13 +# 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* @@ -1283,7 +1283,7 @@ 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 : &:r268_8, ~m270_11 +# 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* @@ -1377,7 +1377,7 @@ ssa.cpp: # 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 : &:r287_9, m287_10 +# 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 @@ -1483,3 +1483,53 @@ ssa.cpp: # 291| v291_10(void) = UnmodeledUse : mu* # 291| v291_11(void) = AliasedUse : ~m295_12 # 291| v291_12(void) = ExitFunction : + +# 301| int main(int, char**) +# 301| Block 0 +# 301| v301_1(void) = EnterFunction : +# 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 +# 302| r302_1(glval) = FunctionAddress[unknownFunction] : +# 302| r302_2(glval) = VariableAddress[argc] : +# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_4(glval) = VariableAddress[argv] : +# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 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| 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_4(glval) = VariableAddress[argv] : +# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 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 +# 303| v303_9(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m303_8 +# 303| m303_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 +# 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_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 : 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 e71995247cc..01af278d8d9 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 @@ -89,7 +89,7 @@ ssa.cpp: # 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 : &:r13_8, m28_3 +# 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* @@ -257,12 +257,12 @@ ssa.cpp: #-----| Goto (back edge) -> Block 1 # 71| Block 3 -# 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection : &: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 : +# 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 : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -803,7 +803,7 @@ ssa.cpp: # 181| r181_3(int *) = Load : &:r181_2, m179_7 # 181| r181_4(int) = Load : &:r181_3, ~m179_9 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection : &:r179_8, m179_9 +# 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* @@ -848,10 +848,10 @@ ssa.cpp: # 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 : &:r184_8, m184_9 -# 184| v184_23(void) = ReturnIndirection : &:r184_12, m184_13 -# 184| v184_24(void) = ReturnIndirection : &:r184_16, m184_17 -# 184| v184_25(void) = ReturnIndirection : &:r184_20, m184_21 +# 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 @@ -908,8 +908,8 @@ 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 : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection : &:r198_12, m198_13 +# 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* @@ -1180,7 +1180,7 @@ 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 : &:r247_8, m249_6 +# 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* @@ -1272,7 +1272,7 @@ ssa.cpp: # 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 : &:r268_8, m268_9 +# 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* @@ -1365,7 +1365,7 @@ ssa.cpp: # 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 : &:r287_9, m287_10 +# 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 @@ -1471,3 +1471,52 @@ ssa.cpp: # 291| v291_10(void) = UnmodeledUse : mu* # 291| v291_11(void) = AliasedUse : ~m295_12 # 291| v291_12(void) = ExitFunction : + +# 301| int main(int, char**) +# 301| Block 0 +# 301| v301_1(void) = EnterFunction : +# 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 +# 302| r302_1(glval) = FunctionAddress[unknownFunction] : +# 302| r302_2(glval) = VariableAddress[argc] : +# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_4(glval) = VariableAddress[argv] : +# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 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| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 +# 302| m302_11(char *) = Chi : total:m301_11, 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_4(glval) = VariableAddress[argv] : +# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 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 +# 304| r304_1(glval) = VariableAddress[#return] : +# 304| r304_2(glval) = VariableAddress[argv] : +# 304| r304_3(char **) = Load : &:r304_2, m301_9 +# 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 : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected index 1e78ae87f40..e2db1e65034 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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 index 1e78ae87f40..f448013286b 100644 --- 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 @@ -1,6 +1,7 @@ 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 @@ -9,6 +10,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges @@ -19,6 +21,7 @@ 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 diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 6c5fd5eaf87..5ea3ef77968 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -294,4 +294,12 @@ Point *NewAliasing(int x) { int j = new A(new A(x))->i; A* a = new A; return p; +} + +void unknownFunction(int argc, char **argv); + +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 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 1e6551dd15a..b307db1cfc5 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 @@ -78,7 +78,7 @@ ssa.cpp: # 28| r28_9(int) = Load : &:r28_8, ~mu13_4 # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection : &:r13_7, ~mu13_4 +# 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* @@ -249,12 +249,12 @@ ssa.cpp: #-----| Goto (back edge) -> Block 1 # 71| Block 3 -# 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection : &: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 : +# 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 : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -752,7 +752,7 @@ ssa.cpp: # 181| r181_3(int *) = Load : &:r181_2, m179_6 # 181| r181_4(int) = Load : &:r181_3, ~mu179_4 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection : &:r179_7, ~mu179_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* @@ -795,10 +795,10 @@ ssa.cpp: # 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 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection : &:r184_19, ~mu184_4 +# 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 @@ -854,8 +854,8 @@ 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 : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection : &:r198_11, ~mu198_4 +# 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* @@ -1098,7 +1098,7 @@ ssa.cpp: # 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 : &:r247_7, ~mu247_4 +# 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* @@ -1183,7 +1183,7 @@ ssa.cpp: # 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 : &:r268_7, ~mu268_4 +# 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* @@ -1267,7 +1267,7 @@ ssa.cpp: # 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 : &:r287_8, ~mu287_4 +# 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 @@ -1359,3 +1359,47 @@ ssa.cpp: # 291| v291_9(void) = UnmodeledUse : mu* # 291| v291_10(void) = AliasedUse : ~mu291_4 # 291| v291_11(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 +# 302| r302_1(glval) = FunctionAddress[unknownFunction] : +# 302| r302_2(glval) = VariableAddress[argc] : +# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_4(glval) = VariableAddress[argv] : +# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 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_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_4(glval) = VariableAddress[argv] : +# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 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_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_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 : 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 1e6551dd15a..b307db1cfc5 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 @@ -78,7 +78,7 @@ ssa.cpp: # 28| r28_9(int) = Load : &:r28_8, ~mu13_4 # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection : &:r13_7, ~mu13_4 +# 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* @@ -249,12 +249,12 @@ ssa.cpp: #-----| Goto (back edge) -> Block 1 # 71| Block 3 -# 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection : &: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 : +# 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 : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -752,7 +752,7 @@ ssa.cpp: # 181| r181_3(int *) = Load : &:r181_2, m179_6 # 181| r181_4(int) = Load : &:r181_3, ~mu179_4 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection : &:r179_7, ~mu179_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* @@ -795,10 +795,10 @@ ssa.cpp: # 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 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection : &:r184_19, ~mu184_4 +# 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 @@ -854,8 +854,8 @@ 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 : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection : &:r198_11, ~mu198_4 +# 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* @@ -1098,7 +1098,7 @@ ssa.cpp: # 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 : &:r247_7, ~mu247_4 +# 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* @@ -1183,7 +1183,7 @@ ssa.cpp: # 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 : &:r268_7, ~mu268_4 +# 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* @@ -1267,7 +1267,7 @@ ssa.cpp: # 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 : &:r287_8, ~mu287_4 +# 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 @@ -1359,3 +1359,47 @@ ssa.cpp: # 291| v291_9(void) = UnmodeledUse : mu* # 291| v291_10(void) = AliasedUse : ~mu291_4 # 291| v291_11(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 +# 302| r302_1(glval) = FunctionAddress[unknownFunction] : +# 302| r302_2(glval) = VariableAddress[argc] : +# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_4(glval) = VariableAddress[argv] : +# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 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_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_4(glval) = VariableAddress[argv] : +# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 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_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_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 : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected index 1e78ae87f40..e2db1e65034 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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_sanity_unsound.expected index 1e78ae87f40..e2db1e65034 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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/cpp/ql/test/library-tests/ir/types/irtypes.expected b/cpp/ql/test/library-tests/ir/types/irtypes.expected new file mode 100644 index 00000000000..e69de29bb2d 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/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/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected index 362983363cc..e54fd26ba1c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected @@ -30,7 +30,6 @@ missingOperand unexpectedOperand duplicateOperand missingPhiOperand -| cpp11.cpp:141:7:141:7 | Phi: g | cpp11.cpp:161:16:161:16 | NoOp: label ...: | missingOperandType duplicateChiOperand sideEffectWithoutPrimary @@ -83,50 +82,48 @@ ambiguousSuccessors | 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 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -213,50 +210,48 @@ ambiguousSuccessors | 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 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -339,10 +334,6 @@ ambiguousSuccessors | 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 | @@ -361,50 +352,48 @@ ambiguousSuccessors | 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 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -425,10 +414,6 @@ ambiguousSuccessors | 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 *)... | @@ -463,50 +448,48 @@ ambiguousSuccessors | 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 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | @@ -524,47 +507,12 @@ ambiguousSuccessors | 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 +memoryOperandDefinitionIsUnmodeled 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 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 76fecc0bf65..1d901ac351f 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. | @@ -796,6 +790,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. | +| file://:0:0:0:0 | 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_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected index cd5366a0c73..1ba36c90051 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected @@ -34,13 +34,6 @@ missingOperand | misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | | misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| 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 @@ -60,6 +53,7 @@ instructionWithoutSuccessor | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | | cpp17.cpp:15:11:15:21 | Convert: (void *)... | +| enum.c:6:9:6:9 | Constant: (int)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | @@ -140,50 +134,48 @@ ambiguousSuccessors | 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 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -270,50 +262,48 @@ ambiguousSuccessors | 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 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -396,10 +386,6 @@ ambiguousSuccessors | 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 | @@ -418,50 +404,48 @@ ambiguousSuccessors | 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 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -482,10 +466,6 @@ ambiguousSuccessors | 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 *)... | @@ -520,50 +500,48 @@ ambiguousSuccessors | 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 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | @@ -581,51 +559,12 @@ ambiguousSuccessors | 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 +memoryOperandDefinitionIsUnmodeled 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*) | 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 index 82b5f5ccef0..f70bf724111 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected @@ -30,16 +30,6 @@ missingOperand 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 @@ -92,50 +82,48 @@ ambiguousSuccessors | 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 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | @@ -222,50 +210,48 @@ ambiguousSuccessors | 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 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | @@ -348,10 +334,6 @@ ambiguousSuccessors | 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 | @@ -370,50 +352,48 @@ ambiguousSuccessors | 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 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | @@ -434,10 +414,6 @@ ambiguousSuccessors | 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 *)... | @@ -472,50 +448,48 @@ ambiguousSuccessors | 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 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | | whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | @@ -533,47 +507,12 @@ ambiguousSuccessors | 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 +memoryOperandDefinitionIsUnmodeled 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 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..fbb93e657fe 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 | 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/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/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index a492fb47d41..54982a6bc37 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,78 @@ 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| mu1_5(unknown) = UnmodeledDefinition : # 1| valnum = unique -# 1| r1_6(glval) = VariableAddress[p0] : +# 1| r1_6(glval) = VariableAddress[p0] : # 1| valnum = r1_6, r5_1, r6_1 -# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 +# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 # 1| valnum = m1_7, r5_2, r6_2 -# 1| r1_8(glval) = VariableAddress[p1] : +# 1| r1_8(glval) = VariableAddress[p1] : # 1| valnum = r1_8, r5_3, r6_3 -# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 +# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 # 1| valnum = m1_9, r5_4, r6_4 -# 2| r2_1(glval) = VariableAddress[x] : +# 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| r5_1(glval) = VariableAddress[p0] : # 5| valnum = r1_6, r5_1, r6_1 -# 5| r5_2(int) = Load : &:r5_1, m1_7 +# 5| r5_2(int) = Load : &:r5_1, m1_7 # 5| valnum = m1_7, r5_2, r6_2 -# 5| r5_3(glval) = VariableAddress[p1] : +# 5| r5_3(glval) = VariableAddress[p1] : # 5| valnum = r1_8, r5_3, r6_3 -# 5| r5_4(int) = Load : &:r5_3, m1_9 +# 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_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| r6_1(glval) = VariableAddress[p0] : # 6| valnum = r1_6, r5_1, r6_1 -# 6| r6_2(int) = Load : &:r6_1, m1_7 +# 6| r6_2(int) = Load : &:r6_1, m1_7 # 6| valnum = m1_7, r5_2, r6_2 -# 6| r6_3(glval) = VariableAddress[p1] : +# 6| r6_3(glval) = VariableAddress[p1] : # 6| valnum = r1_8, r5_3, r6_3 -# 6| r6_4(int) = Load : &:r6_3, m1_9 +# 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_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_10(void) = ReturnVoid : +# 1| v1_11(void) = UnmodeledUse : mu* +# 1| v1_12(void) = AliasedUse : m1_3 +# 1| v1_13(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 : @@ -154,14 +152,12 @@ 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_10(void) = ReturnVoid : +# 12| v12_11(void) = UnmodeledUse : mu* +# 12| v12_12(void) = AliasedUse : m12_3 +# 12| v12_13(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 : @@ -248,14 +244,12 @@ 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_10(void) = ReturnVoid : +# 25| v25_11(void) = UnmodeledUse : mu* +# 25| v25_12(void) = AliasedUse : ~m30_4 +# 25| v25_13(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 : @@ -355,13 +349,11 @@ 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 : &: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_14(void) = ReturnIndirection[p2] : &:r39_12, m44_6 +# 39| v39_15(void) = ReturnVoid : +# 39| v39_16(void) = UnmodeledUse : mu* +# 39| v39_17(void) = AliasedUse : m39_3 +# 39| v39_18(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 @@ -433,27 +425,27 @@ test.cpp: #-----| 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| r56_6(glval) = VariableAddress[str] : # 56| valnum = r49_6, r53_2, r56_6 -# 56| r56_7(char *) = Load : &:r56_6, m49_7 +# 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_8(char) = Load : &:r56_7, ~m49_9 # 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 @@ -531,8 +523,8 @@ test.cpp: # 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 : &:r49_8, m49_9 -# 49| v49_15(void) = ReturnIndirection : &:r49_12, m49_13 +# 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 @@ -625,14 +617,14 @@ test.cpp: #-----| Goto -> Block 2 # 82| Block 2 -# 82| m82_1(unknown) = Phi : from 0:~m77_5, from 1:~m80_4 +# 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 : &: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 : +# 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 : # 84| void test05(int, int, void*) # 84| Block 0 @@ -689,7 +681,7 @@ 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 : &:r84_12, m84_13 +# 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 @@ -818,7 +810,7 @@ test.cpp: # 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 : &:r104_8, m104_9 +# 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 @@ -925,7 +917,7 @@ test.cpp: # 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 : &:r124_8, m128_7 +# 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 @@ -1068,7 +1060,7 @@ test.cpp: # 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 : &:r143_8, m147_7 +# 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 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/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/qlpack.yml b/cpp/ql/test/qlpack.yml index 36dcb70d4ef..008af57baef 100644 --- a/cpp/ql/test/qlpack.yml +++ b/cpp/ql/test/qlpack.yml @@ -1,3 +1,4 @@ name: codeql-cpp-tests version: 0.0.0 libraryPathDependencies: codeql-cpp +extractor: cpp diff --git a/cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.expected b/cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.expected index 7350749ce96..45f88d426c9 100644 --- a/cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.expected +++ b/cpp/ql/test/query-tests/Critical/NewFree/NewFreeMismatch.expected @@ -1,5 +1,9 @@ | test2.cpp:19:3:19:6 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:18:12:18:18 | new | new | | test2.cpp:26:3:26:6 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:25:7:25:13 | new | new | +| test2.cpp:51:2:51:5 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:45:18:45:24 | new | new | +| test2.cpp:55:2:55:5 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test2.cpp:46:20:46:33 | call to operator new | new | +| test2.cpp:57:2:57:18 | delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test2.cpp:47:21:47:26 | call to malloc | malloc | +| test2.cpp:58:2:58:18 | call to operator delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test2.cpp:47:21:47:26 | call to malloc | malloc | | test.cpp:36:2:36:17 | delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test.cpp:27:18:27:23 | call to malloc | malloc | | test.cpp:41:2:41:5 | call to free | There is a new/free mismatch between this free and the corresponding $@. | test.cpp:26:7:26:17 | new | new | | test.cpp:68:3:68:11 | delete | There is a malloc/delete mismatch between this delete and the corresponding $@. | test.cpp:64:28:64:33 | call to malloc | malloc | diff --git a/cpp/ql/test/query-tests/Critical/NewFree/test2.cpp b/cpp/ql/test/query-tests/Critical/NewFree/test2.cpp index 9101758d85b..43a286f6f97 100644 --- a/cpp/ql/test/query-tests/Critical/NewFree/test2.cpp +++ b/cpp/ql/test/query-tests/Critical/NewFree/test2.cpp @@ -34,3 +34,27 @@ public: }; MyTest2Class mt2c_i; + +// --- + +void* operator new(size_t); +void operator delete(void*); + +void test_operator_new() +{ + void *ptr_new = new int; + void *ptr_opnew = ::operator new(sizeof(int)); + void *ptr_malloc = malloc(sizeof(int)); + + delete ptr_new; // GOOD + ::operator delete(ptr_new); // GOOD + free(ptr_new); // BAD + + delete ptr_opnew; // GOOD + ::operator delete(ptr_opnew); // GOOD + free(ptr_opnew); // BAD + + delete ptr_malloc; // BAD + ::operator delete(ptr_malloc); // BAD + free(ptr_malloc); // GOOD +} 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/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 7a58fb1b608..d7db531fbde 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -1 +1,13 @@ -| test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) | +edges +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | +| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | +nodes +| test.c:9:23:9:26 | argv | semmle.label | argv | +| test.c:9:23:9:26 | argv | semmle.label | argv | +| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | +| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... | +| test.c:17:11:17:18 | fileName | semmle.label | fileName | +#select +| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index bfdbb13a097..17bb67fdc08 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -1,2 +1,30 @@ -| search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | -| search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | +edges +| search.c:14:24:14:28 | query | search.c:17:8:17:12 | (const char *)... | +| search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | +| search.c:14:24:14:28 | query | search.c:17:8:17:12 | query | +| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | +| search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | +| search.c:41:21:41:26 | call to getenv | search.c:45:17:45:25 | raw_query | +| search.c:41:21:41:26 | call to getenv | search.c:45:17:45:25 | raw_query | +| search.c:41:21:41:26 | call to getenv | search.c:47:17:47:25 | raw_query | +| search.c:41:21:41:26 | call to getenv | search.c:47:17:47:25 | raw_query | +| search.c:45:17:45:25 | raw_query | search.c:14:24:14:28 | query | +| search.c:47:17:47:25 | raw_query | search.c:22:24:22:28 | query | +nodes +| search.c:14:24:14:28 | query | semmle.label | query | +| search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | +| search.c:17:8:17:12 | (const char *)... | semmle.label | (const char *)... | +| search.c:17:8:17:12 | query | semmle.label | query | +| search.c:17:8:17:12 | query | semmle.label | query | +| search.c:17:8:17:12 | query | semmle.label | query | +| search.c:22:24:22:28 | query | semmle.label | query | +| search.c:23:39:23:43 | query | semmle.label | query | +| search.c:23:39:23:43 | query | semmle.label | query | +| search.c:23:39:23:43 | query | semmle.label | query | +| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | +| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | +| search.c:45:17:45:25 | raw_query | semmle.label | raw_query | +| search.c:47:17:47:25 | raw_query | semmle.label | raw_query | +#select +| search.c:17:8:17:12 | query | search.c:41:21:41:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | +| search.c:23:39:23:43 | query | search.c:41:21:41:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | 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 b494196d4aa..f84c6719157 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 @@ -1,2 +1,25 @@ -| 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 | 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 | +edges +| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | +| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command | +| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | +| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command | +| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command | +| 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 | +nodes +| test.cpp:24:30:24:36 | command | semmle.label | command | +| test.cpp:26:10:26:16 | command | semmle.label | command | +| test.cpp:26:10:26:16 | command | semmle.label | command | +| test.cpp:26:10:26:16 | command | semmle.label | command | +| test.cpp:29:30:29:36 | command | semmle.label | command | +| test.cpp:31:10:31:16 | command | semmle.label | command | +| test.cpp:31:10:31:16 | command | semmle.label | command | +| test.cpp:31:10:31:16 | command | semmle.label | command | +| test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv | +| 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 *)... | +#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 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected index e69de29bb2d..58e3dda0964 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected @@ -0,0 +1,3 @@ +edges +nodes +#select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index 5096e75ebc3..291c1cb3a71 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -1,5 +1,53 @@ -| tests.c:28:3:28:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | -| tests.c:29:3:29:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | -| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | -| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 | -| tests.c:34:25:34:33 | buffer100 | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv | +edges +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | (const char *)... | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | (const char *)... | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | +nodes +| tests.c:28:22:28:25 | argv | semmle.label | argv | +| tests.c:28:22:28:25 | argv | semmle.label | argv | +| tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | +| tests.c:28:22:28:28 | (const char *)... | semmle.label | (const char *)... | +| tests.c:28:22:28:28 | access to array | semmle.label | access to array | +| tests.c:28:22:28:28 | access to array | semmle.label | access to array | +| tests.c:28:22:28:28 | access to array | semmle.label | access to array | +| tests.c:29:28:29:31 | argv | semmle.label | argv | +| tests.c:29:28:29:31 | argv | semmle.label | argv | +| tests.c:29:28:29:34 | access to array | semmle.label | access to array | +| tests.c:29:28:29:34 | access to array | semmle.label | access to array | +| tests.c:29:28:29:34 | access to array | semmle.label | access to array | +| tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | +| tests.c:31:15:31:23 | array to pointer conversion | semmle.label | array to pointer conversion | +| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | +| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | +| tests.c:31:15:31:23 | buffer100 | semmle.label | buffer100 | +| tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | +| tests.c:33:21:33:29 | array to pointer conversion | semmle.label | array to pointer conversion | +| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | +| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | +| tests.c:33:21:33:29 | buffer100 | semmle.label | buffer100 | +| tests.c:34:10:34:13 | argv | semmle.label | argv | +| tests.c:34:10:34:13 | argv | semmle.label | argv | +| tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | +| tests.c:34:10:34:16 | (const char *)... | semmle.label | (const char *)... | +| tests.c:34:10:34:16 | access to array | semmle.label | access to array | +| tests.c:34:10:34:16 | access to array | semmle.label | access to array | +| tests.c:34:10:34:16 | access to array | semmle.label | access to array | +#select +| tests.c:28:3:28:9 | call to sprintf | tests.c:28:22:28:25 | argv | tests.c:28:22:28:28 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv | +| tests.c:29:3:29:9 | call to sprintf | tests.c:29:28:29:31 | argv | tests.c:29:28:29:34 | access to array | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv | +| tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 | +| tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 | +| tests.c:34:25:34:33 | buffer100 | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv | 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 7f342b0aabe..91587aafe8f 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 @@ -1,28 +1,329 @@ -| argvLocal.c:95:9:95:15 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:95:9:95:12 | argv | argv | -| argvLocal.c:96:15:96:21 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:96:15:96:18 | argv | argv | -| argvLocal.c:101:9:101:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | -| argvLocal.c:102:15:102:16 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | -| argvLocal.c:106:9:106:13 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | -| argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | -| argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | -| argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | -| argvLocal.c:116:9:116:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:117:15:117:16 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:121:9:121:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:122:15:122:16 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | -| argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | -| argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | -| argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | -| argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | -| argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv | -| argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv | -| argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv | -| argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv | -| argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv | -| argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | -| argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | +edges +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | (const char *)... | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | (const char *)... | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | +| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | +| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | +| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | +| argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | (const char *)... | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | (const char *)... | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:102:15:102:16 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:102:15:102:16 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:102:15:102:16 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:102:15:102:16 | i1 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | (const char *)... | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | (const char *)... | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | +| argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | (const char *)... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | (const char *)... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | (const char *)... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | (const char *)... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | +| argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | +| 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 | (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 | BufferReadSideEffect | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | BufferReadSideEffect | +| 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 | +| 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 | i3 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | +| 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 | (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 | BufferReadSideEffect | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | BufferReadSideEffect | +| 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 | +| 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 | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | (const char *)... | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | +| argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | +| 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:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:117:15:117:16 | BufferReadSideEffect | 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 | BufferReadSideEffect | +| 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 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:135:9:135:12 | (const char *)... | +| 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 | BufferReadSideEffect | 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 | ... ++ | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | +| argvLocal.c:122:15:122:16 | printWrapper output argument | argvLocal.c:136:15:136:18 | -- ... | +| 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 | (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 | BufferReadSideEffect | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | BufferReadSideEffect | +| 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 | +| 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 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | (const char *)... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | +| argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | +| 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:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:128:15:128:16 | BufferReadSideEffect | 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 | ... + ... | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:128:15:128:16 | printWrapper output argument | argvLocal.c:132:15:132:20 | ... + ... | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | (const char *)... | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | +| argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | (const char *)... | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | (const char *)... | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | +| argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (char *)... | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (const char *)... | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:9:169:20 | (const char *)... | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:15:170:26 | (char *)... | +| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:15:170:26 | (char *)... | +| 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 | +| 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 *)... | +| argvLocal.c:95:9:95:15 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array | +| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array | +| argvLocal.c:95:9:95:15 | access to array | semmle.label | access to array | +| argvLocal.c:96:15:96:18 | argv | semmle.label | argv | +| argvLocal.c:96:15:96:18 | argv | semmle.label | argv | +| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array | +| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array | +| argvLocal.c:96:15:96:21 | access to array | semmle.label | access to array | +| argvLocal.c:100:7:100:10 | argv | semmle.label | argv | +| argvLocal.c:100:7:100:10 | argv | semmle.label | argv | +| argvLocal.c:101:9:101:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:101:9:101:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 | +| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 | +| argvLocal.c:101:9:101:10 | i1 | semmle.label | i1 | +| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 | +| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 | +| argvLocal.c:102:15:102:16 | i1 | semmle.label | i1 | +| argvLocal.c:105:14:105:17 | argv | semmle.label | argv | +| argvLocal.c:105:14:105:17 | argv | semmle.label | argv | +| argvLocal.c:106:9:106:13 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:106:9:106:13 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array | +| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array | +| argvLocal.c:106:9:106:13 | access to array | semmle.label | access to array | +| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array | +| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array | +| argvLocal.c:107:15:107:19 | access to array | semmle.label | access to array | +| argvLocal.c:110:9:110:11 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:110:9:110:11 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... | +| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... | +| argvLocal.c:110:9:110:11 | * ... | semmle.label | * ... | +| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | +| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | +| argvLocal.c:111:15:111:17 | * ... | semmle.label | * ... | +| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | +| argvLocal.c:115:13:115:16 | argv | semmle.label | argv | +| 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 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | +| argvLocal.c:117:15:117:16 | printWrapper output argument | semmle.label | printWrapper output argument | +| 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 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | +| argvLocal.c:122:15:122:16 | printWrapper output argument | semmle.label | printWrapper output argument | +| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | +| argvLocal.c:126:10:126:13 | argv | semmle.label | argv | +| 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 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | +| argvLocal.c:128:15:128:16 | printWrapper output argument | semmle.label | printWrapper output argument | +| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:131:9:131:14 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:131:9:131:14 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:132:15:132:20 | ... + ... | semmle.label | ... + ... | +| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:135:9:135:12 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:135:9:135:12 | ... ++ | semmle.label | ... ++ | +| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | +| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | +| argvLocal.c:136:15:136:18 | -- ... | semmle.label | -- ... | +| argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:144:9:144:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | +| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | +| argvLocal.c:144:9:144:10 | i7 | semmle.label | i7 | +| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 | +| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 | +| argvLocal.c:145:15:145:16 | i7 | semmle.label | i7 | +| argvLocal.c:149:11:149:14 | argv | semmle.label | argv | +| argvLocal.c:149:11:149:14 | argv | semmle.label | argv | +| argvLocal.c:150:9:150:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:150:9:150:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 | +| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 | +| argvLocal.c:150:9:150:10 | i8 | semmle.label | i8 | +| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | +| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | +| argvLocal.c:151:15:151:16 | i8 | semmle.label | i8 | +| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | +| argvLocal.c:156:23:156:26 | argv | semmle.label | argv | +| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:157:9:157:10 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:157:9:157:10 | i9 | semmle.label | i9 | +| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | +| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | +| argvLocal.c:158:15:158:16 | i9 | semmle.label | i9 | +| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | +| argvLocal.c:163:22:163:25 | argv | semmle.label | argv | +| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:164:9:164:11 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:164:9:164:11 | i91 | semmle.label | i91 | +| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | +| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | +| argvLocal.c:165:15:165:17 | i91 | semmle.label | i91 | +| argvLocal.c:168:18:168:21 | argv | semmle.label | argv | +| argvLocal.c:168:18:168:21 | argv | semmle.label | argv | +| argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... | +| argvLocal.c:169:9:169:20 | (char *)... | semmle.label | (char *)... | +| argvLocal.c:169:9:169:20 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:169:9:169:20 | (const char *)... | semmle.label | (const char *)... | +| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 | +| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 | +| argvLocal.c:169:18:169:20 | i10 | semmle.label | i10 | +| argvLocal.c:170:15:170:26 | (char *)... | semmle.label | (char *)... | +| argvLocal.c:170:15:170:26 | (char *)... | semmle.label | (char *)... | +| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 | +| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 | +| argvLocal.c:170:24:170:26 | i10 | semmle.label | i10 | +#select +| argvLocal.c:95:9:95:15 | access to array | argvLocal.c:95:9:95:12 | argv | argvLocal.c:95:9:95:15 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:95:9:95:12 | argv | argv | +| argvLocal.c:96:15:96:21 | access to array | argvLocal.c:96:15:96:18 | argv | argvLocal.c:96:15:96:21 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:96:15:96:18 | argv | argv | +| argvLocal.c:101:9:101:10 | i1 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:101:9:101:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | +| argvLocal.c:102:15:102:16 | i1 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:102:15:102:16 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | +| argvLocal.c:106:9:106:13 | access to array | argvLocal.c:105:14:105:17 | argv | argvLocal.c:106:9:106:13 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:107:15:107:19 | access to array | argvLocal.c:105:14:105:17 | argv | argvLocal.c:107:15:107:19 | access to array | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:110:9:110:11 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:110:9:110:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:111:15:111:17 | * ... | argvLocal.c:105:14:105:17 | argv | argvLocal.c:111:15:111:17 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:105:14:105:17 | argv | argv | +| argvLocal.c:116:9:116:10 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:116:9:116:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:117:15:117:16 | i3 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:121:9:121:10 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:121:9:121:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:122:15:122:16 | i4 | argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:127:9:127:10 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:127:9:127:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:128:15:128:16 | i5 | argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:131:9:131:14 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:131:9:131:14 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:132:15:132:20 | ... + ... | argvLocal.c:126:10:126:13 | argv | argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv | +| argvLocal.c:135:9:135:12 | ... ++ | argvLocal.c:115:13:115:16 | argv | argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:136:15:136:18 | -- ... | argvLocal.c:115:13:115:16 | argv | argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv | +| argvLocal.c:144:9:144:10 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv | +| argvLocal.c:145:15:145:16 | i7 | argvLocal.c:100:7:100:10 | argv | argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv | +| argvLocal.c:150:9:150:10 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:11:149:14 | argv | argv | +| argvLocal.c:151:15:151:16 | i8 | argvLocal.c:149:11:149:14 | argv | argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:11:149:14 | argv | argv | +| argvLocal.c:157:9:157:10 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:157:9:157:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:158:15:158:16 | i9 | argvLocal.c:156:23:156:26 | argv | argvLocal.c:158:15:158:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:156:23:156:26 | argv | argv | +| argvLocal.c:164:9:164:11 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:164:9:164:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:163:22:163:25 | argv | argv | +| argvLocal.c:165:15:165:17 | i91 | argvLocal.c:163:22:163:25 | argv | argvLocal.c:165:15:165:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:163:22:163:25 | argv | argv | +| argvLocal.c:169:18:169:20 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:169:18:169:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:168:18:168:21 | argv | argv | +| argvLocal.c:170:24:170:26 | i10 | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:168:18:168:21 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index 2417990beb2..a05e392ecf2 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -1,7 +1,83 @@ -| funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | -| funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets | -| funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets | -| funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:19:31:21 | i41 | fgets | -| funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets | -| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets | -| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:18:41:20 | i61 | gets | +edges +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | (const char *)... | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | (const char *)... | +| funcsLocal.c:16:8:16:9 | fread output argument | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | (const char *)... | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | (const char *)... | +| funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | (const char *)... | +| funcsLocal.c:26:8:26:9 | fgets output argument | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | (const char *)... | +| funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | (const char *)... | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | (const char *)... | +| funcsLocal.c:31:19:31:21 | fgets output argument | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | (const char *)... | +| funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | (const char *)... | +| funcsLocal.c:36:7:36:8 | gets output argument | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | (const char *)... | +| funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | (const char *)... | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | (const char *)... | +| funcsLocal.c:41:18:41:20 | gets output argument | funcsLocal.c:42:9:42:10 | i6 | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... | +| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | +nodes +| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | +| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | +| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:17:9:17:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:17:9:17:10 | i1 | semmle.label | i1 | +| funcsLocal.c:26:8:26:9 | fgets output argument | semmle.label | fgets output argument | +| funcsLocal.c:26:8:26:9 | i3 | semmle.label | i3 | +| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:27:9:27:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:27:9:27:10 | i3 | semmle.label | i3 | +| funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | +| funcsLocal.c:31:13:31:17 | call to fgets | semmle.label | call to fgets | +| funcsLocal.c:31:19:31:21 | fgets output argument | semmle.label | fgets output argument | +| funcsLocal.c:31:19:31:21 | i41 | semmle.label | i41 | +| funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:32:9:32:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | +| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | +| funcsLocal.c:32:9:32:10 | i4 | semmle.label | i4 | +| funcsLocal.c:36:7:36:8 | gets output argument | semmle.label | gets output argument | +| funcsLocal.c:36:7:36:8 | i5 | semmle.label | i5 | +| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:37:9:37:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:37:9:37:10 | i5 | semmle.label | i5 | +| funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | +| funcsLocal.c:41:13:41:16 | call to gets | semmle.label | call to gets | +| funcsLocal.c:41:18:41:20 | gets output argument | semmle.label | gets output argument | +| funcsLocal.c:41:18:41:20 | i61 | semmle.label | i61 | +| funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:42:9:42:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:42:9:42:10 | i6 | semmle.label | i6 | +| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:58:9:58:10 | (const char *)... | semmle.label | (const char *)... | +| funcsLocal.c:58:9:58:10 | e1 | semmle.label | e1 | +#select +| funcsLocal.c:17:9:17:10 | i1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:17:9:17:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | +| funcsLocal.c:27:9:27:10 | i3 | funcsLocal.c:26:8:26:9 | i3 | funcsLocal.c:27:9:27:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:26:8:26:9 | i3 | fgets | +| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:13:31:17 | call to fgets | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets | +| funcsLocal.c:32:9:32:10 | i4 | funcsLocal.c:31:19:31:21 | i41 | funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:19:31:21 | i41 | fgets | +| funcsLocal.c:37:9:37:10 | i5 | funcsLocal.c:36:7:36:8 | i5 | funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets | +| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:13:41:16 | call to gets | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets | +| funcsLocal.c:42:9:42:10 | i6 | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:18:41:20 | i61 | gets | +| funcsLocal.c:58:9:58:10 | e1 | funcsLocal.c:16:8:16:9 | i1 | funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected index e69de29bb2d..58e3dda0964 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected @@ -0,0 +1,3 @@ +edges +nodes +#select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index 0f29313da8e..ba735a3e140 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -1,5 +1,65 @@ -| globalVars.c:27:9:27:12 | copy | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:8:7:8:10 | copy | copy | globalVars.c:24:11:24:14 | argv | argv | -| globalVars.c:30:15:30:18 | copy | This value may flow through $@, originating from $@, and is a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:8:7:8:10 | copy | copy | globalVars.c:24:11:24:14 | argv | argv | -| globalVars.c:38:9:38:13 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv | -| globalVars.c:41:15:41:19 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printWrapper(str), which calls printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv | -| globalVars.c:50:9:50:13 | copy2 | This value may flow through $@, originating from $@, and is a formatting argument to printf(format). | globalVars.c:9:7:9:11 | copy2 | copy2 | globalVars.c:24:11:24:14 | argv | argv | +edges +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:30:15:30:18 | copy | +| globalVars.c:8:7:8:10 | copy | globalVars.c:35:11:35:14 | copy | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:41:15:41:19 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:9:7:9:11 | copy2 | globalVars.c:50:9:50:13 | copy2 | +| globalVars.c:11:22:11:25 | argv | globalVars.c:12:2:12:15 | Store | +| globalVars.c:12:2:12:15 | Store | globalVars.c:8:7:8:10 | copy | +| globalVars.c:15:21:15:23 | val | globalVars.c:16:2:16:12 | Store | +| globalVars.c:16:2:16:12 | Store | globalVars.c:9:7:9:11 | copy2 | +| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv | +| globalVars.c:24:11:24:14 | argv | globalVars.c:11:22:11:25 | argv | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | (const char *)... | +| globalVars.c:27:9:27:12 | copy | globalVars.c:27:9:27:12 | copy | +| globalVars.c:35:11:35:14 | copy | globalVars.c:15:21:15:23 | val | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | (const char *)... | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:38:9:38:13 | copy2 | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | +nodes +| globalVars.c:8:7:8:10 | copy | semmle.label | copy | +| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | +| globalVars.c:11:22:11:25 | argv | semmle.label | argv | +| globalVars.c:12:2:12:15 | Store | semmle.label | Store | +| globalVars.c:15:21:15:23 | val | semmle.label | val | +| globalVars.c:16:2:16:12 | Store | semmle.label | Store | +| globalVars.c:24:11:24:14 | argv | semmle.label | argv | +| globalVars.c:24:11:24:14 | argv | semmle.label | argv | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:27:9:27:12 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:30:15:30:18 | copy | semmle.label | copy | +| globalVars.c:35:11:35:14 | copy | semmle.label | copy | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:38:9:38:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:38:9:38:13 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:41:15:41:19 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:50:9:50:13 | (const char *)... | semmle.label | (const char *)... | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +| globalVars.c:50:9:50:13 | copy2 | semmle.label | copy2 | +#select +| globalVars.c:27:9:27:12 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:27:9:27:12 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | globalVars.c:24:11:24:14 | argv | argv | +| globalVars.c:30:15:30:18 | copy | globalVars.c:24:11:24:14 | argv | globalVars.c:30:15:30:18 | copy | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format) | globalVars.c:24:11:24:14 | argv | argv | +| globalVars.c:38:9:38:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:38:9:38:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | globalVars.c:24:11:24:14 | argv | argv | +| globalVars.c:41:15:41:19 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:41:15:41:19 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(str), which calls printf(format) | globalVars.c:24:11:24:14 | argv | argv | +| globalVars.c:50:9:50:13 | copy2 | globalVars.c:24:11:24:14 | argv | globalVars.c:50:9:50:13 | copy2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | globalVars.c:24:11:24:14 | argv | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected index d474364a0cc..62c36d0192d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected @@ -1,11 +1,157 @@ -| ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:61:8:61:11 | argv | argv | -| ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv | -| ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv | -| ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv | -| ifs.c:87:9:87:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:86:8:86:11 | argv | argv | -| ifs.c:93:9:93:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:92:8:92:11 | argv | argv | -| ifs.c:99:9:99:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:98:8:98:11 | argv | argv | -| ifs.c:106:9:106:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:105:8:105:11 | argv | argv | -| ifs.c:112:9:112:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:111:8:111:11 | argv | argv | -| ifs.c:118:9:118:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:117:8:117:11 | argv | argv | -| ifs.c:124:9:124:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:123:8:123:11 | argv | argv | +edges +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | (const char *)... | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | +| ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | (const char *)... | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | +| ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | (const char *)... | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | +| ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | (const char *)... | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | +| ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | (const char *)... | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | +| ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | (const char *)... | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | +| ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | (const char *)... | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | +| ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | (const char *)... | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | +| ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | (const char *)... | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | +| ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | (const char *)... | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | +| ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | (const char *)... | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | +| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | +nodes +| ifs.c:61:8:61:11 | argv | semmle.label | argv | +| ifs.c:61:8:61:11 | argv | semmle.label | argv | +| ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:62:9:62:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:62:9:62:10 | c7 | semmle.label | c7 | +| ifs.c:62:9:62:10 | c7 | semmle.label | c7 | +| ifs.c:62:9:62:10 | c7 | semmle.label | c7 | +| ifs.c:68:8:68:11 | argv | semmle.label | argv | +| ifs.c:68:8:68:11 | argv | semmle.label | argv | +| ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:69:9:69:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:69:9:69:10 | c8 | semmle.label | c8 | +| ifs.c:69:9:69:10 | c8 | semmle.label | c8 | +| ifs.c:69:9:69:10 | c8 | semmle.label | c8 | +| ifs.c:74:8:74:11 | argv | semmle.label | argv | +| ifs.c:74:8:74:11 | argv | semmle.label | argv | +| ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:75:9:75:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:75:9:75:10 | i1 | semmle.label | i1 | +| ifs.c:75:9:75:10 | i1 | semmle.label | i1 | +| ifs.c:75:9:75:10 | i1 | semmle.label | i1 | +| ifs.c:80:8:80:11 | argv | semmle.label | argv | +| ifs.c:80:8:80:11 | argv | semmle.label | argv | +| ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:81:9:81:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:81:9:81:10 | i2 | semmle.label | i2 | +| ifs.c:81:9:81:10 | i2 | semmle.label | i2 | +| ifs.c:81:9:81:10 | i2 | semmle.label | i2 | +| ifs.c:86:8:86:11 | argv | semmle.label | argv | +| ifs.c:86:8:86:11 | argv | semmle.label | argv | +| ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:87:9:87:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:87:9:87:10 | i3 | semmle.label | i3 | +| ifs.c:87:9:87:10 | i3 | semmle.label | i3 | +| ifs.c:87:9:87:10 | i3 | semmle.label | i3 | +| ifs.c:92:8:92:11 | argv | semmle.label | argv | +| ifs.c:92:8:92:11 | argv | semmle.label | argv | +| ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:93:9:93:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:93:9:93:10 | i4 | semmle.label | i4 | +| ifs.c:93:9:93:10 | i4 | semmle.label | i4 | +| ifs.c:93:9:93:10 | i4 | semmle.label | i4 | +| ifs.c:98:8:98:11 | argv | semmle.label | argv | +| ifs.c:98:8:98:11 | argv | semmle.label | argv | +| ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:99:9:99:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:99:9:99:10 | i5 | semmle.label | i5 | +| ifs.c:99:9:99:10 | i5 | semmle.label | i5 | +| ifs.c:99:9:99:10 | i5 | semmle.label | i5 | +| ifs.c:105:8:105:11 | argv | semmle.label | argv | +| ifs.c:105:8:105:11 | argv | semmle.label | argv | +| ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:106:9:106:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:106:9:106:10 | i6 | semmle.label | i6 | +| ifs.c:106:9:106:10 | i6 | semmle.label | i6 | +| ifs.c:106:9:106:10 | i6 | semmle.label | i6 | +| ifs.c:111:8:111:11 | argv | semmle.label | argv | +| ifs.c:111:8:111:11 | argv | semmle.label | argv | +| ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:112:9:112:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:112:9:112:10 | i7 | semmle.label | i7 | +| ifs.c:112:9:112:10 | i7 | semmle.label | i7 | +| ifs.c:112:9:112:10 | i7 | semmle.label | i7 | +| ifs.c:117:8:117:11 | argv | semmle.label | argv | +| ifs.c:117:8:117:11 | argv | semmle.label | argv | +| ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:118:9:118:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:118:9:118:10 | i8 | semmle.label | i8 | +| ifs.c:118:9:118:10 | i8 | semmle.label | i8 | +| ifs.c:118:9:118:10 | i8 | semmle.label | i8 | +| ifs.c:123:8:123:11 | argv | semmle.label | argv | +| ifs.c:123:8:123:11 | argv | semmle.label | argv | +| ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:124:9:124:10 | (const char *)... | semmle.label | (const char *)... | +| ifs.c:124:9:124:10 | i9 | semmle.label | i9 | +| ifs.c:124:9:124:10 | i9 | semmle.label | i9 | +| ifs.c:124:9:124:10 | i9 | semmle.label | i9 | +#select +| ifs.c:62:9:62:10 | c7 | ifs.c:61:8:61:11 | argv | ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:61:8:61:11 | argv | argv | +| ifs.c:69:9:69:10 | c8 | ifs.c:68:8:68:11 | argv | ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv | +| ifs.c:75:9:75:10 | i1 | ifs.c:74:8:74:11 | argv | ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv | +| ifs.c:81:9:81:10 | i2 | ifs.c:80:8:80:11 | argv | ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv | +| ifs.c:87:9:87:10 | i3 | ifs.c:86:8:86:11 | argv | ifs.c:87:9:87:10 | i3 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:86:8:86:11 | argv | argv | +| ifs.c:93:9:93:10 | i4 | ifs.c:92:8:92:11 | argv | ifs.c:93:9:93:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:92:8:92:11 | argv | argv | +| ifs.c:99:9:99:10 | i5 | ifs.c:98:8:98:11 | argv | ifs.c:99:9:99:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:98:8:98:11 | argv | argv | +| ifs.c:106:9:106:10 | i6 | ifs.c:105:8:105:11 | argv | ifs.c:106:9:106:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:105:8:105:11 | argv | argv | +| ifs.c:112:9:112:10 | i7 | ifs.c:111:8:111:11 | argv | ifs.c:112:9:112:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:111:8:111:11 | argv | argv | +| ifs.c:118:9:118:10 | i8 | ifs.c:117:8:117:11 | argv | ifs.c:118:9:118:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:117:8:117:11 | argv | argv | +| ifs.c:124:9:124:10 | i9 | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:123:8:123:11 | argv | argv | 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 f77bf73d52d..773a969e9ad 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 @@ -1,9 +1,138 @@ -| test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:43:31:43:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:45:31:45:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:52:21:52:27 | call to realloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | -| test.cpp:127:17:127:22 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:123:25:123:30 | call to getenv | user input (getenv) | +edges +| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | +| test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | +| 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:42:38:42: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 | ... * ... | +| test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | +| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | +| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | +| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | +| test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | (size_t)... | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | (size_t)... | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:48:32:48:35 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | +| test.cpp:39:21:39:24 | argv | test.cpp:49:26:49:29 | size | +| 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:35:52:60 | ... * ... | +| 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: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: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: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: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: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 | +nodes +| test.cpp:39:21:39:24 | argv | semmle.label | argv | +| test.cpp:39:21:39:24 | argv | semmle.label | argv | +| test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | +| 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:63 | ... * ... | semmle.label | ... * ... | +| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | +| test.cpp:43:38:43:63 | ... * ... | semmle.label | ... * ... | +| test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | +| test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | +| test.cpp:45:38:45:63 | ... + ... | semmle.label | ... + ... | +| test.cpp:48:32:48:35 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:48:32:48:35 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:48:32:48:35 | size | semmle.label | size | +| test.cpp:48:32:48:35 | size | semmle.label | size | +| test.cpp:48:32:48:35 | size | semmle.label | size | +| test.cpp:49:26:49:29 | size | semmle.label | size | +| test.cpp:49:26:49:29 | size | semmle.label | size | +| test.cpp:49:26:49:29 | size | semmle.label | size | +| 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: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: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: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: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)... | +#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: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: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: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: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: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) | 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 5cd5f0c0246..cb21e8f1915 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]; @@ -39,10 +39,10 @@ int main(int argc, char **argv) { int tainted = atoi(argv[1]); MyStruct *arr1 = (MyStruct *)malloc(sizeof(MyStruct)); // GOOD - MyStruct *arr2 = (MyStruct *)malloc(tainted); // BAD + MyStruct *arr2 = (MyStruct *)malloc(tainted); // DUBIOUS (not multiplied by anything) MyStruct *arr3 = (MyStruct *)malloc(tainted * sizeof(MyStruct)); // BAD MyStruct *arr4 = (MyStruct *)malloc(getTainted() * sizeof(MyStruct)); // BAD [NOT DETECTED] - MyStruct *arr5 = (MyStruct *)malloc(sizeof(MyStruct) + tainted); // BAD [NOT DETECTED] + MyStruct *arr5 = (MyStruct *)malloc(sizeof(MyStruct) + tainted); // DUBIOUS (not multiplied by anything) int size = tainted * 8; char *chars1 = (char *)malloc(size); // BAD @@ -52,7 +52,7 @@ int main(int argc, char **argv) { arr1 = (MyStruct *)realloc(arr1, sizeof(MyStruct) * tainted); // BAD size = 8; - chars3 = new char[size]; // GOOD [FALSE POSITIVE] + chars3 = new char[size]; // GOOD return 0; } @@ -120,9 +120,119 @@ int bounded(int x, int limit) { } void open_file_bounded () { - int size = size = atoi(getenv("USER")); + int size = atoi(getenv("USER")); int bounded_size = bounded(size, MAX_SIZE); - int* a = (int*)malloc(bounded_size); // GOOD - int* b = (int*)malloc(size); // BAD -} \ No newline at end of file + int* a = (int*)malloc(bounded_size * sizeof(int)); // GOOD + int* b = (int*)malloc(size * sizeof(int)); // BAD +} + +void more_bounded_tests() { + { + int size = atoi(getenv("USER")); + + malloc(size * sizeof(int)); // BAD + } + + { + int size = atoi(getenv("USER")); + + if (size > 0) + { + malloc(size * sizeof(int)); // BAD + } + } + + { + int size = atoi(getenv("USER")); + + if (size < 100) + { + malloc(size * sizeof(int)); // BAD [NOT DETECTED] + } + } + + { + int size = atoi(getenv("USER")); + + if ((size > 0) && (size < 100)) + { + malloc(size * sizeof(int)); // GOOD + } + } + + { + int size = atoi(getenv("USER")); + + if ((100 > size) && (0 < size)) + { + malloc(size * sizeof(int)); // GOOD + } + } + + { + int size = atoi(getenv("USER")); + + malloc(size * sizeof(int)); // BAD [NOT DETECTED] + + if ((size > 0) && (size < 100)) + { + // ... + } + } + + { + int size = atoi(getenv("USER")); + + if (size > 100) + { + malloc(size * sizeof(int)); // BAD [NOT DETECTED] + } + } +} + +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 +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected index 860ef74fdff..f68464b6b38 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected @@ -1,9 +1,138 @@ -| test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value | -| test.c:35:5:35:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:34:13:34:18 | call to rand | Uncontrolled value | -| test.c:40:5:40:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:39:13:39:21 | ... % ... | Uncontrolled value | -| test.c:45:5:45:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:44:13:44:16 | call to rand | Uncontrolled value | -| test.c:56:5:56:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:13:54:16 | call to rand | Uncontrolled value | -| test.c:67:5:67:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:66:13:66:16 | call to rand | Uncontrolled value | -| test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value | -| test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value | -| test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value | +edges +| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | +| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | +| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | +| test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | +| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | +| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | +| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | +| test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | +| test.c:39:13:39:21 | ... % ... | test.c:40:5:40:5 | r | +| test.c:39:13:39:21 | ... % ... | test.c:40:5:40:5 | r | +| test.c:39:13:39:21 | ... % ... | test.c:40:5:40:5 | r | +| test.c:39:13:39:21 | ... % ... | test.c:40:5:40:5 | r | +| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | +| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | +| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | +| test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | +| test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | +| test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | +| test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | +| test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:61:5:61:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:61:5:61:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:61:5:61:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:61:5:61:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:62:5:62:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:62:5:62:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:62:5:62:5 | r | +| test.c:60:13:60:16 | call to rand | test.c:62:5:62:5 | r | +| test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | +| test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | +| test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | +| test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | +| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | +| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | +| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | +| test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | +| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | +| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | +| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | +| test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | +| test.cpp:8:9:8:12 | Store | test.cpp:24:11:24:18 | call to get_rand | +| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | +| test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | +| test.cpp:13:2:13:15 | Chi | test.cpp:30:13:30:14 | get_rand2 output argument | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi | +| test.cpp:18:2:18:14 | Chi | test.cpp:36:13:36:13 | get_rand3 output argument | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi | +| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | +| test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | +nodes +| test.c:18:13:18:16 | call to rand | semmle.label | call to rand | +| test.c:18:13:18:16 | call to rand | semmle.label | call to rand | +| test.c:21:17:21:17 | r | semmle.label | r | +| test.c:21:17:21:17 | r | semmle.label | r | +| test.c:21:17:21:17 | r | semmle.label | r | +| test.c:34:13:34:18 | call to rand | semmle.label | call to rand | +| test.c:34:13:34:18 | call to rand | semmle.label | call to rand | +| test.c:35:5:35:5 | r | semmle.label | r | +| test.c:35:5:35:5 | r | semmle.label | r | +| test.c:35:5:35:5 | r | semmle.label | r | +| test.c:39:13:39:21 | ... % ... | semmle.label | ... % ... | +| test.c:39:13:39:21 | ... % ... | semmle.label | ... % ... | +| test.c:40:5:40:5 | r | semmle.label | r | +| test.c:40:5:40:5 | r | semmle.label | r | +| test.c:40:5:40:5 | r | semmle.label | r | +| test.c:44:13:44:16 | call to rand | semmle.label | call to rand | +| test.c:44:13:44:16 | call to rand | semmle.label | call to rand | +| test.c:45:5:45:5 | r | semmle.label | r | +| test.c:45:5:45:5 | r | semmle.label | r | +| test.c:45:5:45:5 | r | semmle.label | r | +| test.c:54:13:54:16 | call to rand | semmle.label | call to rand | +| test.c:54:13:54:16 | call to rand | semmle.label | call to rand | +| test.c:56:5:56:5 | r | semmle.label | r | +| test.c:56:5:56:5 | r | semmle.label | r | +| test.c:56:5:56:5 | r | semmle.label | r | +| test.c:60:13:60:16 | call to rand | semmle.label | call to rand | +| test.c:60:13:60:16 | call to rand | semmle.label | call to rand | +| test.c:61:5:61:5 | r | semmle.label | r | +| test.c:61:5:61:5 | r | semmle.label | r | +| test.c:61:5:61:5 | r | semmle.label | r | +| test.c:62:5:62:5 | r | semmle.label | r | +| test.c:62:5:62:5 | r | semmle.label | r | +| test.c:62:5:62:5 | r | semmle.label | r | +| test.c:66:13:66:16 | call to rand | semmle.label | call to rand | +| test.c:66:13:66:16 | call to rand | semmle.label | call to rand | +| test.c:67:5:67:5 | r | semmle.label | r | +| test.c:67:5:67:5 | r | semmle.label | r | +| test.c:67:5:67:5 | r | semmle.label | r | +| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... | +| test.c:75:13:75:19 | ... ^ ... | semmle.label | ... ^ ... | +| test.c:77:9:77:9 | r | semmle.label | r | +| test.c:77:9:77:9 | r | semmle.label | r | +| test.c:77:9:77:9 | r | semmle.label | r | +| test.c:99:14:99:19 | call to rand | semmle.label | call to rand | +| test.c:99:14:99:19 | call to rand | semmle.label | call to rand | +| test.c:100:5:100:5 | r | semmle.label | r | +| test.c:100:5:100:5 | r | semmle.label | r | +| test.c:100:5:100:5 | r | semmle.label | r | +| test.cpp:8:9:8:12 | Store | semmle.label | Store | +| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | +| test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | +| test.cpp:13:2:13:15 | Chi | semmle.label | Chi | +| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | +| test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | +| test.cpp:18:2:18:14 | Chi | semmle.label | Chi | +| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | +| test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | +| test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand | +| test.cpp:25:7:25:7 | r | semmle.label | r | +| test.cpp:25:7:25:7 | r | semmle.label | r | +| test.cpp:25:7:25:7 | r | semmle.label | r | +| test.cpp:30:13:30:14 | get_rand2 output argument | semmle.label | get_rand2 output argument | +| test.cpp:31:7:31:7 | r | semmle.label | r | +| test.cpp:31:7:31:7 | r | semmle.label | r | +| test.cpp:31:7:31:7 | r | semmle.label | r | +| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | +| test.cpp:37:7:37:7 | r | semmle.label | r | +| test.cpp:37:7:37:7 | r | semmle.label | r | +| test.cpp:37:7:37:7 | r | semmle.label | r | +#select +| test.c:21:17:21:17 | r | test.c:18:13:18:16 | call to rand | test.c:21:17:21:17 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:18:13:18:16 | call to rand | Uncontrolled value | +| test.c:35:5:35:5 | r | test.c:34:13:34:18 | call to rand | test.c:35:5:35:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:34:13:34:18 | call to rand | Uncontrolled value | +| test.c:40:5:40:5 | r | test.c:39:13:39:21 | ... % ... | test.c:40:5:40:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:39:13:39:21 | ... % ... | Uncontrolled value | +| test.c:45:5:45:5 | r | test.c:44:13:44:16 | call to rand | test.c:45:5:45:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:44:13:44:16 | call to rand | Uncontrolled value | +| test.c:56:5:56:5 | r | test.c:54:13:54:16 | call to rand | test.c:56:5:56:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:13:54:16 | call to rand | Uncontrolled value | +| test.c:67:5:67:5 | r | test.c:66:13:66:16 | call to rand | test.c:67:5:67:5 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:66:13:66:16 | call to rand | Uncontrolled value | +| test.c:77:9:77:9 | r | test.c:75:13:75:19 | ... ^ ... | test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value | +| test.c:100:5:100:5 | r | test.c:99:14:99:19 | call to rand | test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value | +| test.cpp:25:7:25:7 | r | test.cpp:8:9:8:12 | call to rand | test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value | +| test.cpp:31:7:31:7 | r | test.cpp:13:10:13:13 | call to rand | test.cpp:31:7:31:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:13:10:13:13 | call to rand | Uncontrolled value | +| test.cpp:37:7:37:7 | r | test.cpp:18:9:18:12 | call to rand | test.cpp:37:7:37:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | Uncontrolled value | 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-290/semmle/AuthenticationBypass/AuthenticationBypass.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected index ded1524cfca..e2671c07952 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected @@ -1,3 +1,33 @@ -| test.cpp:20:7:20:12 | call to strcmp | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv | -| test.cpp:31:7:31:12 | call to strcmp | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:27:25:27:30 | call to getenv | call to getenv | -| test.cpp:42:7:42:12 | call to strcmp | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:38:25:38:30 | call to getenv | call to getenv | +edges +| test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | +| test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | +| test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | +| test.cpp:16:25:16:42 | (const char *)... | test.cpp:20:14:20:20 | address | +| test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | +| test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | +| test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | +| test.cpp:27:25:27:42 | (const char *)... | test.cpp:31:14:31:20 | address | +| test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | +| test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | +| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | +| test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | +nodes +| test.cpp:16:25:16:30 | call to getenv | semmle.label | call to getenv | +| test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:20:14:20:20 | address | semmle.label | address | +| test.cpp:20:14:20:20 | address | semmle.label | address | +| test.cpp:20:14:20:20 | address | semmle.label | address | +| test.cpp:27:25:27:30 | call to getenv | semmle.label | call to getenv | +| test.cpp:27:25:27:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:31:14:31:20 | address | semmle.label | address | +| test.cpp:31:14:31:20 | address | semmle.label | address | +| test.cpp:31:14:31:20 | address | semmle.label | address | +| test.cpp:38:25:38:30 | call to getenv | semmle.label | call to getenv | +| test.cpp:38:25:38:42 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:42:14:42:20 | address | semmle.label | address | +| test.cpp:42:14:42:20 | address | semmle.label | address | +| test.cpp:42:14:42:20 | address | semmle.label | address | +#select +| test.cpp:20:7:20:12 | call to strcmp | test.cpp:16:25:16:30 | call to getenv | test.cpp:20:14:20:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:16:25:16:30 | call to getenv | call to getenv | +| test.cpp:31:7:31:12 | call to strcmp | test.cpp:27:25:27:30 | call to getenv | test.cpp:31:14:31:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:27:25:27:30 | call to getenv | call to getenv | +| test.cpp:42:7:42:12 | call to strcmp | test.cpp:38:25:38:30 | call to getenv | test.cpp:42:14:42:20 | address | Untrusted input $@ might be vulnerable to a spoofing attack. | test.cpp:38:25:38:30 | call to getenv | call to getenv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected index 30b971f13e7..f78d75eeed1 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected @@ -1 +1,13 @@ -| test.cpp:58:3:58:9 | call to sprintf | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (argv) | +edges +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | +| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | +nodes +| test.cpp:54:17:54:20 | argv | semmle.label | argv | +| test.cpp:54:17:54:20 | argv | semmle.label | argv | +| test.cpp:58:25:58:29 | input | semmle.label | input | +| test.cpp:58:25:58:29 | input | semmle.label | input | +| test.cpp:58:25:58:29 | input | semmle.label | input | +#select +| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (argv) | 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..4794d4744af --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected @@ -0,0 +1 @@ +| 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 | 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..6433523d69a --- /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 + } +} + + +void test3() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + file1.set("d.txt"); + + create(file1); + if (!rename(file1, file2)) + { + remove(file1); // BAD [NOT DETECTED] + } +} 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/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected index 0ae48831c80..cc5004047cf 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected @@ -1,2 +1,37 @@ -| test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | -| test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... | +edges +| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:16 | call to strcmp | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:16 | call to strcmp | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:24:11:24:35 | (bool)... | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:10:41:38 | ! ... | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:16 | call to strcmp | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:16 | call to strcmp | +| test.cpp:20:29:20:34 | call to getenv | test.cpp:41:11:41:38 | (bool)... | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:10:24:35 | ! ... | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:35 | (bool)... | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:10:41:38 | ! ... | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | +| test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:38 | (bool)... | +| test.cpp:24:11:24:16 | call to strcmp | test.cpp:24:10:24:35 | ! ... | +| test.cpp:24:11:24:16 | call to strcmp | test.cpp:24:11:24:35 | (bool)... | +| test.cpp:41:11:41:16 | call to strcmp | test.cpp:41:10:41:38 | ! ... | +| test.cpp:41:11:41:16 | call to strcmp | test.cpp:41:11:41:38 | (bool)... | +nodes +| test.cpp:20:29:20:34 | call to getenv | semmle.label | call to getenv | +| test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:24:10:24:35 | ! ... | semmle.label | ! ... | +| test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | +| test.cpp:24:11:24:16 | call to strcmp | semmle.label | call to strcmp | +| test.cpp:24:11:24:35 | (bool)... | semmle.label | (bool)... | +| test.cpp:24:11:24:35 | (bool)... | semmle.label | (bool)... | +| test.cpp:41:10:41:38 | ! ... | semmle.label | ! ... | +| test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | +| test.cpp:41:11:41:16 | call to strcmp | semmle.label | call to strcmp | +| test.cpp:41:11:41:38 | (bool)... | semmle.label | (bool)... | +| test.cpp:41:11:41:38 | (bool)... | semmle.label | (bool)... | +#select +| test.cpp:24:10:24:35 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... | +| test.cpp:41:10:41:38 | ! ... | test.cpp:20:29:20:34 | call to getenv | test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... | 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 a2e59cf7ac3..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,13 +334,15 @@ 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"; + Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; + Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; @@ -364,8 +366,7 @@ namespace Semmle.Extraction.Tests Actions.GetCurrentDirectory = cwd; Actions.IsWindows = isWindows; - var options = new AutobuildOptions(); - options.ReadEnvironment(Actions); + var options = new AutobuildOptions(Actions); return new Autobuilder(Actions, options); } @@ -461,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; @@ -732,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; @@ -763,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; @@ -810,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; @@ -836,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; @@ -1030,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/AspBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs index b5b3dfcf61d..f9c690c273b 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs @@ -7,10 +7,9 @@ { public BuildScript Analyse(Autobuilder builder, bool auto) { - (var javaHome, var dist) = - builder.CodeQLJavaHome != null ? - (builder.CodeQLJavaHome, builder.CodeQLExtractorCSharpRoot) : - (builder.SemmleJavaHome, builder.SemmleDist); + var javaHome = builder.JavaHome; + var dist = builder.Distribution; + var command = new CommandBuilder(builder.Actions). RunCommand(builder.Actions.PathCombine(javaHome, "bin", "java")). Argument("-jar"). diff --git a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs b/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs index 740b740f9fb..9786e4dcca6 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs +++ b/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs @@ -10,40 +10,40 @@ namespace Semmle.Autobuild public class AutobuildOptions { public readonly int SearchDepth = 3; - public string RootDirectory = null; - static readonly string prefix = "LGTM_INDEX_"; + public readonly string RootDirectory; + private const string prefix = "LGTM_INDEX_"; - public string VsToolsVersion; - public string MsBuildArguments; - public string MsBuildPlatform; - public string MsBuildConfiguration; - public string MsBuildTarget; - public string DotNetArguments; - public string DotNetVersion; - public string BuildCommand; - public string[] Solution; + public readonly string? VsToolsVersion; + public readonly string? MsBuildArguments; + public readonly string? MsBuildPlatform; + public readonly string? MsBuildConfiguration; + public readonly string? MsBuildTarget; + public readonly string? DotNetArguments; + public readonly string? DotNetVersion; + public readonly string? BuildCommand; + public readonly string[] Solution; - public bool IgnoreErrors; - public bool Buildless; - public bool AllSolutions; - public bool NugetRestore; + public readonly bool IgnoreErrors; + public readonly bool Buildless; + public readonly bool AllSolutions; + public readonly bool NugetRestore; - public Language Language; - public bool Indexing; + public readonly Language Language; + public readonly bool Indexing; /// /// Reads options from environment variables. /// Throws ArgumentOutOfRangeException for invalid arguments. /// - public void ReadEnvironment(IBuildActions actions) + public AutobuildOptions(IBuildActions actions) { RootDirectory = actions.GetCurrentDirectory(); VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION"); - MsBuildArguments = actions.GetEnvironmentVariable(prefix + "MSBUILD_ARGUMENTS").AsStringWithExpandedEnvVars(actions); + MsBuildArguments = actions.GetEnvironmentVariable(prefix + "MSBUILD_ARGUMENTS")?.AsStringWithExpandedEnvVars(actions); MsBuildPlatform = actions.GetEnvironmentVariable(prefix + "MSBUILD_PLATFORM"); MsBuildConfiguration = actions.GetEnvironmentVariable(prefix + "MSBUILD_CONFIGURATION"); MsBuildTarget = actions.GetEnvironmentVariable(prefix + "MSBUILD_TARGET"); - DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS").AsStringWithExpandedEnvVars(actions); + DotNetArguments = actions.GetEnvironmentVariable(prefix + "DOTNET_ARGUMENTS")?.AsStringWithExpandedEnvVars(actions); DotNetVersion = actions.GetEnvironmentVariable(prefix + "DOTNET_VERSION"); BuildCommand = actions.GetEnvironmentVariable(prefix + "BUILD_COMMAND"); Solution = actions.GetEnvironmentVariable(prefix + "SOLUTION").AsListWithExpandedEnvVars(actions, new string[0]); @@ -60,7 +60,7 @@ namespace Semmle.Autobuild public static class OptionsExtensions { - public static bool AsBool(this string value, string param, bool defaultValue) + public static bool AsBool(this string? value, string param, bool defaultValue) { if (value == null) return defaultValue; switch (value.ToLower()) @@ -80,7 +80,7 @@ namespace Semmle.Autobuild } } - public static Language AsLanguage(this string key) + public static Language AsLanguage(this string? key) { switch (key) { @@ -95,7 +95,7 @@ namespace Semmle.Autobuild } } - public static string[] AsListWithExpandedEnvVars(this string value, IBuildActions actions, string[] defaultValue) + public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActions actions, string[] defaultValue) { if (value == null) return defaultValue; diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs index 73e6fcd181f..a882f5bb80c 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs @@ -20,6 +20,14 @@ namespace Semmle.Autobuild BuildScript Analyse(Autobuilder builder, bool auto); } + /// + /// Exception indicating that environment variables are missing or invalid. + /// + class InvalidEnvironmentException : Exception + { + public InvalidEnvironmentException(string m) : base(m) { } + } + /// /// Main application logic, containing all data /// gathered from the project and filesystem. @@ -69,7 +77,7 @@ namespace Semmle.Autobuild /// List of project/solution files to build. /// public IList ProjectsOrSolutionsToBuild => projectsOrSolutionsToBuildLazy.Value; - readonly Lazy> projectsOrSolutionsToBuildLazy; + private readonly Lazy> projectsOrSolutionsToBuildLazy; /// /// Holds if a given path was found. @@ -110,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. @@ -129,7 +155,7 @@ namespace Semmle.Autobuild projectsOrSolutionsToBuildLazy = new Lazy>(() => { - List ret; + List? ret; if (options.Solution.Any()) { ret = new List(); @@ -143,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) @@ -177,19 +185,34 @@ namespace Semmle.Autobuild }); CodeQLExtractorCSharpRoot = Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_ROOT"); - - CodeQLJavaHome = Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME"); - SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); - - SemmleJavaHome = Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME"); - SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); - if (CodeQLExtractorCSharpRoot == null && SemmleDist == null) - Log(Severity.Error, "The environment variables CODEQL_EXTRACTOR_CSHARP_ROOT and SEMMLE_DIST have not been set."); + JavaHome = + Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ?? + Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? + throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set."); + + Distribution = + CodeQLExtractorCSharpRoot ?? + SemmleDist ?? + throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set."); + + TrapDir = + Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? + Actions.GetEnvironmentVariable("TRAP_FOLDER") ?? + throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_TRAP_DIR or TRAP_FOLDER has not been set."); + + SourceArchiveDir = + Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? + Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ?? + throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); } + private string TrapDir { get; } + + private string SourceArchiveDir { get; } + readonly ILogger logger = new ConsoleLogger(Verbosity.Info); /// @@ -271,9 +294,9 @@ namespace Semmle.Autobuild break; case CSharpBuildStrategy.Auto: var cleanTrapFolder = - BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? Actions.GetEnvironmentVariable("TRAP_FOLDER")); + BuildScript.DeleteDirectory(TrapDir); var cleanSourceArchive = - BuildScript.DeleteDirectory(Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? Actions.GetEnvironmentVariable("SOURCE_ARCHIVE")); + BuildScript.DeleteDirectory(SourceArchiveDir); var tryCleanExtractorArgsLogs = BuildScript.Create(actions => { @@ -376,38 +399,33 @@ namespace Semmle.Autobuild /// /// Value of CODEQL_EXTRACTOR_CSHARP_ROOT environment variable. /// - public string CodeQLExtractorCSharpRoot { get; private set; } - - /// - /// Value of CODEQL_JAVA_HOME environment variable. - /// - public string CodeQLJavaHome { get; private set; } + private string? CodeQLExtractorCSharpRoot { get; } /// /// Value of SEMMLE_DIST environment variable. /// - public string SemmleDist { get; private set; } + private string? SemmleDist { get; } - /// - /// Value of SEMMLE_JAVA_HOME environment variable. - /// - public string SemmleJavaHome { get; private set; } + public string Distribution { get; } + + public string JavaHome { get; } /// /// Value of SEMMLE_PLATFORM_TOOLS environment variable. /// - public string SemmlePlatformTools { get; private set; } + public string? SemmlePlatformTools { get; } /// /// The absolute path of the odasa executable. + /// null if we are running in CodeQL. /// - public string Odasa => SemmleDist == null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa"); + public string? Odasa => SemmleDist is null ? null : Actions.PathCombine(SemmleDist, "tools", "odasa"); /// /// Construct a command that executed the given wrapped in /// an odasa --index, unless indexing has been disabled, in which case /// is run directly. /// - internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); + internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs index 837f6e3f69e..7bc4b9b7591 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs @@ -21,7 +21,7 @@ namespace Semmle.Autobuild /// Additional environment variables. /// The lines of stdout. /// The process exit code. - int RunProcess(string exe, string args, string workingDirectory, IDictionary env, out IList stdOut); + int RunProcess(string exe, string args, string? workingDirectory, IDictionary? env, out IList stdOut); /// /// Runs a process but does not capture its output. @@ -31,7 +31,7 @@ namespace Semmle.Autobuild /// The working directory (null for current directory). /// Additional environment variables. /// The process exit code. - int RunProcess(string exe, string args, string workingDirectory, IDictionary env); + int RunProcess(string exe, string args, string? workingDirectory, IDictionary? env); /// /// Tests whether a file exists, File.Exists(). @@ -63,7 +63,7 @@ namespace Semmle.Autobuild /// /// The name of the variable. /// The string value, or null if the variable is not defined. - string GetEnvironmentVariable(string name); + string? GetEnvironmentVariable(string name); /// /// Gets the current directory, Directory.GetCurrentDirectory(). @@ -130,7 +130,7 @@ namespace Semmle.Autobuild bool IBuildActions.FileExists(string file) => File.Exists(file); - ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string workingDirectory, IDictionary environment, bool redirectStandardOutput) + ProcessStartInfo GetProcessStartInfo(string exe, string arguments, string? workingDirectory, IDictionary? environment, bool redirectStandardOutput) { var pi = new ProcessStartInfo(exe, arguments) { @@ -146,7 +146,7 @@ namespace Semmle.Autobuild return pi; } - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary environment) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? environment) { var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false); using (var p = Process.Start(pi)) @@ -156,7 +156,7 @@ namespace Semmle.Autobuild } } - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary environment, out IList stdOut) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? environment, out IList stdOut) { var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, true); return pi.ReadOutput(out stdOut); @@ -166,7 +166,7 @@ namespace Semmle.Autobuild bool IBuildActions.DirectoryExists(string dir) => Directory.Exists(dir); - string IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name); + string? IBuildActions.GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name); string IBuildActions.GetCurrentDirectory() => Directory.GetCurrentDirectory(); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs b/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs index e7e2c9255dd..80a819f403e 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs @@ -40,7 +40,7 @@ namespace Semmle.Autobuild chmod.RunCommand("/bin/chmod", $"u+x {scriptPath}"); var chmodScript = builder.Actions.IsWindows() ? BuildScript.Success : BuildScript.Try(chmod.Script); - var dir = Path.GetDirectoryName(scriptPath); + string? dir = Path.GetDirectoryName(scriptPath); // A specific .NET Core version may be required return chmodScript & DotNetRule.WithDotNet(builder, environment => diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs index 93ea941d58b..e441030ff77 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs @@ -48,8 +48,9 @@ namespace Semmle.Autobuild class BuildCommand : BuildScript { - readonly string exe, arguments, workingDirectory; - readonly IDictionary environment; + readonly string exe, arguments; + readonly string? workingDirectory; + readonly IDictionary? environment; readonly bool silent; /// @@ -60,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 ?? ""; @@ -131,8 +132,8 @@ namespace Semmle.Autobuild class BindBuildScript : BuildScript { readonly BuildScript s1; - readonly Func, int, BuildScript> s2a; - readonly Func s2b; + readonly Func, int, BuildScript>? s2a; + readonly Func? s2b; public BindBuildScript(BuildScript s1, Func, int, BuildScript> s2) { this.s1 = s1; @@ -154,14 +155,19 @@ namespace Semmle.Autobuild return s2a(stdout1, ret1).Run(actions, startCallback, exitCallBack); } - ret1 = s1.Run(actions, startCallback, exitCallBack); - return s2b(ret1).Run(actions, startCallback, exitCallBack); + if (s2b != null) + { + ret1 = s1.Run(actions, startCallback, exitCallBack); + return s2b(ret1).Run(actions, startCallback, exitCallBack); + } + + throw new InvalidOperationException("Unexpected error"); } public override int Run(IBuildActions actions, Action startCallback, Action exitCallBack, out IList stdout) { var ret1 = s1.Run(actions, startCallback, exitCallBack, out var stdout1); - var ret2 = (s2a != null ? s2a(stdout1, ret1) : s2b(ret1)).Run(actions, startCallback, exitCallBack, out var stdout2); + var ret2 = (s2a != null ? s2a(stdout1, ret1) : s2b!(ret1)).Run(actions, startCallback, exitCallBack, out var stdout2); var @out = new List(); @out.AddRange(stdout1); @out.AddRange(stdout2); @@ -177,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 7b95e495697..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; @@ -13,10 +13,10 @@ namespace Semmle.Autobuild readonly StringBuilder arguments; bool firstCommand; - string executable; + string? executable; readonly EscapeMode escapingMode; - readonly string workingDirectory; - readonly IDictionary environment; + readonly string? workingDirectory; + readonly IDictionary? environment; readonly bool silent; /// @@ -25,7 +25,7 @@ namespace Semmle.Autobuild /// The working directory (null for current directory). /// Additional environment variables. /// Whether this command should be run silently. - public CommandBuilder(IBuildActions actions, string workingDirectory = null, IDictionary environment = null, bool silent = false) + public CommandBuilder(IBuildActions actions, string? workingDirectory = null, IDictionary? environment = null, bool silent = false) { arguments = new StringBuilder(); if (actions.IsWindows()) @@ -50,7 +50,7 @@ namespace Semmle.Autobuild RunCommand(odasa, "index --auto"); } - public CommandBuilder CallBatFile(string batFile, string argumentsOpt = null) + public CommandBuilder CallBatFile(string batFile, string? argumentsOpt = null) { NextCommand(); arguments.Append(" CALL"); @@ -66,7 +66,7 @@ namespace Semmle.Autobuild /// The command to run. /// Additional arguments. /// this for chaining calls. - public CommandBuilder IndexCommand(string odasa, string command, string argumentsOpt = null) + public CommandBuilder IndexCommand(string odasa, string command, string? argumentsOpt = null) { OdasaIndex(odasa); QuoteArgument(command); @@ -151,7 +151,7 @@ namespace Semmle.Autobuild arguments.Append(' '); } - public CommandBuilder Argument(string argumentsOpt) + public CommandBuilder Argument(string? argumentsOpt) { if (argumentsOpt != null) { @@ -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); @@ -193,6 +196,14 @@ namespace Semmle.Autobuild /// /// Returns a build script that contains just this command. /// - public BuildScript Script => BuildScript.Create(executable, arguments.ToString(), silent, workingDirectory, environment); + public BuildScript Script + { + get + { + if (executable is null) + throw new System.InvalidOperationException("executable is null"); + return BuildScript.Create(executable, arguments.ToString(), silent, workingDirectory, environment); + } + } } } diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs index f3b81665fca..21215af8434 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs @@ -56,13 +56,13 @@ namespace Semmle.Autobuild }); } - static BuildScript WithDotNet(Autobuilder builder, Func, bool, BuildScript> f) + static BuildScript WithDotNet(Autobuilder builder, Func?, bool, BuildScript> f) { - var installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet"); + string? installDir = builder.Actions.PathCombine(builder.Options.RootDirectory, ".dotnet"); var installScript = DownloadDotNet(builder, installDir); return BuildScript.Bind(installScript, installed => { - Dictionary env; + Dictionary? env; if (installed == 0) { // The installation succeeded, so use the newly installed .NET Core @@ -120,7 +120,7 @@ namespace Semmle.Autobuild /// variables needed by the installed .NET Core (null when no variables /// are needed). /// - public static BuildScript WithDotNet(Autobuilder builder, Func, BuildScript> f) + public static BuildScript WithDotNet(Autobuilder builder, Func?, BuildScript> f) => WithDotNet(builder, (_1, env, _2) => f(env)); /// @@ -265,10 +265,10 @@ Invoke-Command -ScriptBlock $ScriptBlock"; return listSdks.Script; } - static string DotNetCommand(IBuildActions actions, string dotNetPath) => + static string DotNetCommand(IBuildActions actions, string? dotNetPath) => dotNetPath != null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet"; - BuildScript GetInfoCommand(IBuildActions actions, string dotNetPath, IDictionary environment) + BuildScript GetInfoCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var info = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -276,7 +276,7 @@ Invoke-Command -ScriptBlock $ScriptBlock"; return info.Script; } - CommandBuilder GetCleanCommand(IBuildActions actions, string dotNetPath, IDictionary environment) + CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var clean = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -284,7 +284,7 @@ Invoke-Command -ScriptBlock $ScriptBlock"; return clean; } - CommandBuilder GetRestoreCommand(IBuildActions actions, string dotNetPath, IDictionary environment) + CommandBuilder GetRestoreCommand(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var restore = new CommandBuilder(actions, null, environment). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -292,7 +292,7 @@ Invoke-Command -ScriptBlock $ScriptBlock"; return restore; } - static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string dotNetPath, IDictionary environment) + static BuildScript GetInstalledRuntimesScript(IBuildActions actions, string? dotNetPath, IDictionary? environment) { var listSdks = new CommandBuilder(actions, environment: environment, silent: true). RunCommand(DotNetCommand(actions, dotNetPath)). @@ -309,7 +309,7 @@ Invoke-Command -ScriptBlock $ScriptBlock"; /// hence the need for CLR tracing), by adding a /// `/p:UseSharedCompilation=false` argument. /// - BuildScript GetBuildScript(Autobuilder builder, string dotNetPath, IDictionary environment, bool compatibleClr, string projOrSln) + BuildScript GetBuildScript(Autobuilder builder, string? dotNetPath, IDictionary? environment, bool compatibleClr, string projOrSln) { var build = new CommandBuilder(builder.Actions, null, environment); var script = builder.MaybeIndex(build, DotNetCommand(builder.Actions, dotNetPath)). diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs index b0ee01b8d3c..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); @@ -67,10 +74,10 @@ namespace Semmle.Autobuild string target = builder.Options.MsBuildTarget != null ? builder.Options.MsBuildTarget : "rebuild"; - string platform = builder.Options.MsBuildPlatform != null + string? platform = builder.Options.MsBuildPlatform != null ? builder.Options.MsBuildPlatform : projectOrSolution is ISolution s1 ? s1.DefaultPlatformName : null; - string configuration = builder.Options.MsBuildConfiguration != null + string? configuration = builder.Options.MsBuildConfiguration != null ? builder.Options.MsBuildConfiguration : projectOrSolution is ISolution s2 ? s2.DefaultConfigurationName : null; @@ -96,9 +103,9 @@ namespace Semmle.Autobuild /// /// Returns null when no version is specified. /// - public static VcVarsBatFile GetVcVarsBatFile(Autobuilder builder) + public static VcVarsBatFile? GetVcVarsBatFile(Autobuilder builder) { - VcVarsBatFile vsTools = null; + VcVarsBatFile? vsTools = null; if (builder.Options.VsToolsVersion != null) { diff --git a/csharp/autobuilder/Semmle.Autobuild/Program.cs b/csharp/autobuilder/Semmle.Autobuild/Program.cs index c4542864a09..e4bccb0e626 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Program.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Program.cs @@ -6,23 +6,27 @@ namespace Semmle.Autobuild { static int Main() { - var options = new AutobuildOptions(); - var actions = SystemBuildActions.Instance; try { - options.ReadEnvironment(actions); + var actions = SystemBuildActions.Instance; + var options = new AutobuildOptions(actions); + try + { + Console.WriteLine($"Semmle autobuilder for {options.Language}"); + var builder = new Autobuilder(actions, options); + return builder.AttemptBuild(); + } + catch(InvalidEnvironmentException ex) + { + Console.WriteLine("The environment is invalid: {0}", ex.Message); + } } catch (ArgumentOutOfRangeException ex) { Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName); } - - var builder = new Autobuilder(actions, options); - - Console.WriteLine($"Semmle autobuilder for {options.Language}"); - - return builder.AttemptBuild(); + return 1; } } } diff --git a/csharp/autobuilder/Semmle.Autobuild/Project.cs b/csharp/autobuilder/Semmle.Autobuild/Project.cs index 0080f170c54..415ddcbc0f0 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Project.cs @@ -82,7 +82,7 @@ namespace Semmle.Autobuild foreach (var include in projectFileIncludes.Concat(projectFilesIncludes)) { var includePath = builder.Actions.PathCombine(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries)); - ret.Add(new Project(builder, builder.Actions.PathCombine(Path.GetDirectoryName(this.FullPath), includePath))); + ret.Add(new Project(builder, builder.Actions.PathCombine(DirectoryName, includePath))); } return ret; }); diff --git a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs b/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs index 53025345b69..13859a8c0eb 100644 --- a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs +++ b/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; namespace Semmle.Autobuild @@ -24,6 +25,8 @@ namespace Semmle.Autobuild { public string FullPath { get; private set; } + public string DirectoryName => Path.GetDirectoryName(FullPath) ?? ""; + protected ProjectOrSolution(Autobuilder builder, string path) { FullPath = builder.Actions.GetFullPath(path); diff --git a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj b/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj index 5e3f2295ad0..63aab3b29fb 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj +++ b/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj @@ -9,6 +9,7 @@ false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/autobuilder/Semmle.Autobuild/Solution.cs b/csharp/autobuilder/Semmle.Autobuild/Solution.cs index 661f46199f8..0429b9f420c 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Solution.cs @@ -43,7 +43,7 @@ namespace Semmle.Autobuild /// class Solution : ProjectOrSolution, ISolution { - readonly SolutionFile solution; + readonly SolutionFile? solution; readonly IEnumerable includedProjects; public override IEnumerable IncludedProjects => includedProjects; @@ -81,7 +81,7 @@ namespace Semmle.Autobuild includedProjects = solution.ProjectsInOrder. Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat). - Select(p => builder.Actions.PathCombine(Path.GetDirectoryName(path), builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))). + Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))). Select(p => new Project(builder, p)). ToArray(); } diff --git a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs index 366ce1f08fc..26bc84bb601 100644 --- a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs @@ -1,6 +1,4 @@ -using System.IO; - -namespace Semmle.Autobuild +namespace Semmle.Autobuild { /// /// Build using standalone extraction. @@ -9,8 +7,11 @@ namespace Semmle.Autobuild { public BuildScript Analyse(Autobuilder builder, bool auto) { - BuildScript GetCommand(string solution) + BuildScript GetCommand(string? solution) { + if (builder.SemmlePlatformTools is null) + return BuildScript.Failure; + var standalone = builder.Actions.PathCombine(builder.SemmlePlatformTools, "csharp", "Semmle.Extraction.CSharp.Standalone"); var cmd = new CommandBuilder(builder.Actions); cmd.RunCommand(standalone); diff --git a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs index 5814c2b63d2..d9b05dbe0a9 100644 --- a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs @@ -7,7 +7,7 @@ { public BuildScript Analyse(Autobuilder builder, bool auto) { - if (!builder.Options.Indexing) + if (!builder.Options.Indexing || builder.Odasa is null) return BuildScript.Success; var command = new CommandBuilder(builder.Actions). diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs index db2664bf4c9..f93911b8a38 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/AssemblyCache.cs @@ -163,7 +163,19 @@ namespace Semmle.BuildAnalyser /// /// The filename to query. /// The assembly info. - public AssemblyInfo GetAssemblyInfo(string filepath) => assemblyInfo[filepath]; + public AssemblyInfo GetAssemblyInfo(string filepath) + { + if(assemblyInfo.TryGetValue(filepath, out var info)) + { + return info; + } + else + { + info = AssemblyInfo.ReadFromFile(filepath); + assemblyInfo.Add(filepath, info); + return info; + } + } // List of pending DLLs to index. readonly List dlls = new List(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs index b0ef328bcd0..2894222ca89 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/BuildAnalysis.cs @@ -1,10 +1,13 @@ -using System; +using Semmle.Util; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Runtime.InteropServices; -using Semmle.Util; using Semmle.Extraction.CSharp.Standalone; +using System.Threading.Tasks; +using System.Collections.Concurrent; +using System.Text; +using System.Security.Cryptography; namespace Semmle.BuildAnalyser { @@ -43,19 +46,18 @@ namespace Semmle.BuildAnalyser /// /// Main implementation of the build analysis. /// - class BuildAnalysis : IBuildAnalysis + class BuildAnalysis : IBuildAnalysis, IDisposable { - readonly AssemblyCache assemblyCache; - readonly NugetPackages nuget; - readonly IProgressMonitor progressMonitor; - HashSet usedReferences = new HashSet(); - readonly HashSet usedSources = new HashSet(); - readonly HashSet missingSources = new HashSet(); - readonly Dictionary unresolvedReferences = new Dictionary(); - readonly DirectoryInfo sourceDir; - int failedProjects, succeededProjects; - readonly string[] allSources; - int conflictedReferences = 0; + private readonly AssemblyCache assemblyCache; + private readonly NugetPackages nuget; + private readonly IProgressMonitor progressMonitor; + private readonly IDictionary usedReferences = new ConcurrentDictionary(); + private readonly IDictionary sources = new ConcurrentDictionary(); + private readonly IDictionary unresolvedReferences = new ConcurrentDictionary(); + private readonly DirectoryInfo sourceDir; + private int failedProjects, succeededProjects; + private readonly string[] allSources; + private int conflictedReferences = 0; /// /// Performs a C# build analysis. @@ -64,6 +66,8 @@ namespace Semmle.BuildAnalyser /// Display of analysis progress. public BuildAnalysis(Options options, IProgressMonitor progress) { + var startTime = DateTime.Now; + progressMonitor = progress; sourceDir = new DirectoryInfo(options.SrcDir); @@ -74,36 +78,43 @@ namespace Semmle.BuildAnalyser Where(d => !options.ExcludesFile(d)). ToArray(); - var dllDirNames = options.DllDirs.Select(Path.GetFullPath); + var dllDirNames = options.DllDirs.Select(Path.GetFullPath).ToList(); + PackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName)); if (options.UseNuGet) { - nuget = new NugetPackages(sourceDir.FullName); - ReadNugetFiles(); - dllDirNames = dllDirNames.Concat(Enumerators.Singleton(nuget.PackageDirectory)); + try + { + nuget = new NugetPackages(sourceDir.FullName, PackageDirectory); + ReadNugetFiles(); + } + catch(FileNotFoundException) + { + progressMonitor.MissingNuGet(); + } } // Find DLLs in the .Net Framework if (options.ScanNetFrameworkDlls) { - dllDirNames = dllDirNames.Concat(Runtime.Runtimes.Take(1)); + dllDirNames.Add(Runtime.Runtimes.First()); } - assemblyCache = new BuildAnalyser.AssemblyCache(dllDirNames, progress); + // These files can sometimes prevent `dotnet restore` from working correctly. + using (new FileRenamer(sourceDir.GetFiles("global.json", SearchOption.AllDirectories))) + using (new FileRenamer(sourceDir.GetFiles("Directory.Build.props", SearchOption.AllDirectories))) + { + var solutions = options.SolutionFile != null ? + new[] { options.SolutionFile } : + sourceDir.GetFiles("*.sln", SearchOption.AllDirectories).Select(d => d.FullName); - // Analyse all .csproj files in the source tree. - if (options.SolutionFile != null) - { - AnalyseSolution(options.SolutionFile); - } - else if (options.AnalyseCsProjFiles) - { - AnalyseProjectFiles(); - } + RestoreSolutions(solutions); + dllDirNames.Add(PackageDirectory.DirInfo.FullName); + assemblyCache = new BuildAnalyser.AssemblyCache(dllDirNames, progress); + AnalyseSolutions(solutions); - if (!options.AnalyseCsProjFiles) - { - usedReferences = new HashSet(assemblyCache.AllAssemblies.Select(a => a.Filename)); + foreach (var filename in assemblyCache.AllAssemblies.Select(a => a.Filename)) + UseReference(filename); } ResolveConflicts(); @@ -114,7 +125,7 @@ namespace Semmle.BuildAnalyser } // Output the findings - foreach (var r in usedReferences) + foreach (var r in usedReferences.Keys) { progressMonitor.ResolvedReference(r); } @@ -132,7 +143,27 @@ namespace Semmle.BuildAnalyser UnresolvedReferences.Count(), conflictedReferences, succeededProjects + failedProjects, - failedProjects); + failedProjects, + DateTime.Now - startTime); + } + + /// + /// Computes a unique temp directory for the packages associated + /// with this source tree. Use a SHA1 of the directory name. + /// + /// + /// The full path of the temp directory. + private static string ComputeTempDirectory(string srcDir) + { + var bytes = Encoding.Unicode.GetBytes(srcDir); + + using var sha1 = new SHA1CryptoServiceProvider(); + var sha = sha1.ComputeHash(bytes); + var sb = new StringBuilder(); + foreach (var b in sha.Take(8)) + sb.AppendFormat("{0:x2}", b); + + return Path.Combine(Path.GetTempPath(), "GitHub", "packages", sb.ToString()); } /// @@ -143,7 +174,7 @@ namespace Semmle.BuildAnalyser void ResolveConflicts() { var sortedReferences = usedReferences. - Select(r => assemblyCache.GetAssemblyInfo(r)). + Select(r => assemblyCache.GetAssemblyInfo(r.Key)). OrderBy(r => r.Version). ToArray(); @@ -154,7 +185,9 @@ namespace Semmle.BuildAnalyser finalAssemblyList[r.Name] = r; // Update the used references list - usedReferences = new HashSet(finalAssemblyList.Select(r => r.Value.Filename)); + usedReferences.Clear(); + foreach (var r in finalAssemblyList.Select(r => r.Value.Filename)) + UseReference(r); // Report the results foreach (var r in sortedReferences) @@ -183,7 +216,7 @@ namespace Semmle.BuildAnalyser /// The filename of the reference. void UseReference(string reference) { - usedReferences.Add(reference); + usedReferences[reference] = true; } /// @@ -192,25 +225,18 @@ namespace Semmle.BuildAnalyser /// The source file. void UseSource(FileInfo sourceFile) { - if (sourceFile.Exists) - { - usedSources.Add(sourceFile.FullName); - } - else - { - missingSources.Add(sourceFile.FullName); - } + sources[sourceFile.FullName] = sourceFile.Exists; } /// /// The list of resolved reference files. /// - public IEnumerable ReferenceFiles => this.usedReferences; + public IEnumerable ReferenceFiles => this.usedReferences.Keys; /// /// The list of source files used in projects. /// - public IEnumerable ProjectSourceFiles => usedSources; + public IEnumerable ProjectSourceFiles => sources.Where(s => s.Value).Select(s => s.Key); /// /// All of the source files in the source directory. @@ -226,7 +252,7 @@ namespace Semmle.BuildAnalyser /// List of source files which were mentioned in project files but /// do not exist on the file system. /// - public IEnumerable MissingSourceFiles => missingSources; + public IEnumerable MissingSourceFiles => sources.Where(s => !s.Value).Select(s => s.Key); /// /// Record that a particular reference couldn't be resolved. @@ -239,74 +265,101 @@ namespace Semmle.BuildAnalyser unresolvedReferences[id] = projectFile; } - /// - /// Performs an analysis of all .csproj files. - /// - void AnalyseProjectFiles() - { - AnalyseProjectFiles(sourceDir.GetFiles("*.csproj", SearchOption.AllDirectories)); - } + readonly TemporaryDirectory PackageDirectory; /// /// Reads all the source files and references from the given list of projects. /// /// The list of projects to analyse. - void AnalyseProjectFiles(FileInfo[] projectFiles) + void AnalyseProjectFiles(IEnumerable projectFiles) { - progressMonitor.AnalysingProjectFiles(projectFiles.Count()); - foreach (var proj in projectFiles) + AnalyseProject(proj); + } + + void AnalyseProject(FileInfo project) + { + if(!project.Exists) { - try - { - var csProj = new CsProjFile(proj); + progressMonitor.MissingProject(project.FullName); + return; + } - foreach (var @ref in csProj.References) - { - AssemblyInfo resolved = assemblyCache.ResolveReference(@ref); - if (!resolved.Valid) - { - UnresolvedReference(@ref, proj.FullName); - } - else - { - UseReference(resolved.Filename); - } - } + try + { + var csProj = new CsProjFile(project); - foreach (var src in csProj.Sources) - { - // Make a note of which source files the projects use. - // This information doesn't affect the build but is dumped - // as diagnostic output. - UseSource(new FileInfo(src)); - } - ++succeededProjects; - } - catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + foreach (var @ref in csProj.References) { - ++failedProjects; - progressMonitor.FailedProjectFile(proj.FullName, ex.Message); + AssemblyInfo resolved = assemblyCache.ResolveReference(@ref); + if (!resolved.Valid) + { + UnresolvedReference(@ref, project.FullName); + } + else + { + UseReference(resolved.Filename); + } } + + foreach (var src in csProj.Sources) + { + // Make a note of which source files the projects use. + // This information doesn't affect the build but is dumped + // as diagnostic output. + UseSource(new FileInfo(src)); + } + + ++succeededProjects; + } + catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] + { + ++failedProjects; + progressMonitor.FailedProjectFile(project.FullName, ex.Message); + } + + } + + void Restore(string projectOrSolution) + { + int exit = DotNet.RestoreToDirectory(projectOrSolution, PackageDirectory.DirInfo.FullName); + switch(exit) + { + case 0: + case 1: + // No errors + break; + default: + progressMonitor.CommandFailed("dotnet", $"restore \"{projectOrSolution}\"", exit); + break; } } - /// - /// Delete packages directory. - /// - public void Cleanup() + public void RestoreSolutions(IEnumerable solutions) { - if (nuget != null) nuget.Cleanup(progressMonitor); + Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = 4 }, Restore); } - /// - /// Analyse all project files in a given solution only. - /// - /// The filename of the solution. - public void AnalyseSolution(string solutionFile) + public void AnalyseSolutions(IEnumerable solutions) { - var sln = new SolutionFile(solutionFile); - AnalyseProjectFiles(sln.Projects.Select(p => new FileInfo(p)).ToArray()); + Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = 4 } , solutionFile => + { + try + { + var sln = new SolutionFile(solutionFile); + progressMonitor.AnalysingSolution(solutionFile); + AnalyseProjectFiles(sln.Projects.Select(p => new FileInfo(p)).Where(p => p.Exists)); + } + catch (Microsoft.Build.Exceptions.InvalidProjectFileException ex) + { + progressMonitor.FailedProjectFile(solutionFile, ex.BaseMessage); + } + }); + } + + public void Dispose() + { + PackageDirectory?.Dispose(); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs index 2c9e72c1eaa..1083c9b6257 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs @@ -10,12 +10,18 @@ namespace Semmle.BuildAnalyser /// class CsProjFile { + private string Filename { get; } + + private string Directory => Path.GetDirectoryName(Filename); + /// /// Reads the .csproj file. /// /// The .csproj file. public CsProjFile(FileInfo filename) { + Filename = filename.FullName; + try { // This can fail if the .csproj is invalid or has @@ -39,7 +45,7 @@ namespace Semmle.BuildAnalyser /// and there seems to be no way to make it succeed. Fails on Linux. /// /// The file to read. - public void ReadMsBuildProject(FileInfo filename) + private void ReadMsBuildProject(FileInfo filename) { var msbuildProject = new Microsoft.Build.Execution.ProjectInstance(filename.FullName); @@ -62,7 +68,7 @@ namespace Semmle.BuildAnalyser /// fallback if ReadMsBuildProject() fails. /// /// The .csproj file. - public void ReadProjectFileAsXml(FileInfo filename) + private void ReadProjectFileAsXml(FileInfo filename) { var projFile = new XmlDocument(); var mgr = new XmlNamespaceManager(projFile.NameTable); @@ -71,22 +77,48 @@ namespace Semmle.BuildAnalyser var projDir = filename.Directory; var root = projFile.DocumentElement; - references = - root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Reference/@Include", mgr). - NodeList(). - Select(node => node.Value). - ToArray(); + // Figure out if it's dotnet core - var relativeCsIncludes = - root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Compile/@Include", mgr). - NodeList(). - Select(node => node.Value). - ToArray(); + bool netCoreProjectFile = root.GetAttribute("Sdk") == "Microsoft.NET.Sdk"; - csFiles = relativeCsIncludes. - Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs). - Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))). - ToArray(); + if (netCoreProjectFile) + { + var relativeCsIncludes = + root.SelectNodes("/Project/ItemGroup/Compile/@Include", mgr). + NodeList(). + Select(node => node.Value). + ToArray(); + + var explicitCsFiles = relativeCsIncludes. + Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs). + Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))); + + var additionalCsFiles = System.IO.Directory.GetFiles(Directory, "*.cs", SearchOption.AllDirectories); + + csFiles = explicitCsFiles.Concat(additionalCsFiles).ToArray(); + + references = new string[0]; + } + else + { + + references = + root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Reference/@Include", mgr). + NodeList(). + Select(node => node.Value). + ToArray(); + + var relativeCsIncludes = + root.SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Compile/@Include", mgr). + NodeList(). + Select(node => node.Value). + ToArray(); + + csFiles = relativeCsIncludes. + Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs). + Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))). + ToArray(); + } } string[] references; diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs new file mode 100644 index 00000000000..6edd217af8d --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/DotNet.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; + +namespace Semmle.BuildAnalyser +{ + /// + /// Utilities to run the "dotnet" command. + /// + static class DotNet + { + public static int RestoreToDirectory(string projectOrSolutionFile, string packageDirectory) + { + using var proc = Process.Start("dotnet", $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true"); + proc.WaitForExit(); + return proc.ExitCode; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs index 1f0755f307f..2ea3afb6c69 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs @@ -1,10 +1,9 @@ -using System; +using Semmle.Util; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Security.Cryptography; -using System.Text; namespace Semmle.BuildAnalyser { @@ -19,10 +18,10 @@ namespace Semmle.BuildAnalyser /// Create the package manager for a specified source tree. /// /// The source directory. - public NugetPackages(string sourceDir) + public NugetPackages(string sourceDir, TemporaryDirectory packageDirectory) { SourceDirectory = sourceDir; - PackageDirectory = computeTempDirectory(sourceDir); + PackageDirectory = packageDirectory; // Expect nuget.exe to be in a `nuget` directory under the directory containing this exe. var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location; @@ -50,45 +49,12 @@ namespace Semmle.BuildAnalyser /// public IEnumerable PackageFiles => packages; - // Whether to delete the packages directory prior to each run. - // Makes each build more reproducible. - const bool cleanupPackages = true; - - public void Cleanup(IProgressMonitor pm) - { - var packagesDirectory = new DirectoryInfo(PackageDirectory); - - if (packagesDirectory.Exists) - { - try - { - packagesDirectory.Delete(true); - } - catch (System.IO.IOException ex) - { - pm.Warning(string.Format("Couldn't delete package directory - it's probably held open by something else: {0}", ex.Message)); - } - } - } - /// /// Download the packages to the temp folder. /// /// The progress monitor used for reporting errors etc. public void InstallPackages(IProgressMonitor pm) { - if (cleanupPackages) - { - Cleanup(pm); - } - - var packagesDirectory = new DirectoryInfo(PackageDirectory); - - if (!Directory.Exists(PackageDirectory)) - { - packagesDirectory.Create(); - } - foreach (var package in packages) { RestoreNugetPackage(package.FullName, pm); @@ -109,31 +75,7 @@ namespace Semmle.BuildAnalyser /// This will be in the Temp location /// so as to not trample the source tree. /// - public string PackageDirectory - { - get; - private set; - } - - readonly SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); - - /// - /// Computes a unique temp directory for the packages associated - /// with this source tree. Use a SHA1 of the directory name. - /// - /// - /// The full path of the temp directory. - string computeTempDirectory(string srcDir) - { - var bytes = Encoding.Unicode.GetBytes(srcDir); - - var sha = sha1.ComputeHash(bytes); - var sb = new StringBuilder(); - foreach (var b in sha.Take(8)) - sb.AppendFormat("{0:x2}", b); - - return Path.Combine(Path.GetTempPath(), "Semmle", "packages", sb.ToString()); - } + public TemporaryDirectory PackageDirectory { get; } /// /// Restore all files in a specified package. @@ -171,16 +113,15 @@ namespace Semmle.BuildAnalyser try { - using (var p = Process.Start(pi)) - { - string output = p.StandardOutput.ReadToEnd(); - string error = p.StandardError.ReadToEnd(); + using var p = Process.Start(pi); - p.WaitForExit(); - if (p.ExitCode != 0) - { - pm.FailedNugetCommand(pi.FileName, pi.Arguments, output + error); - } + string output = p.StandardOutput.ReadToEnd(); + string error = p.StandardError.ReadToEnd(); + + p.WaitForExit(); + if (p.ExitCode != 0) + { + pm.FailedNugetCommand(pi.FileName, pi.Arguments, output + error); } } catch (Exception ex) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs index e0367fa63c1..106771faef2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Standalone /// /// Searches for source/references and creates separate extractions. /// - class Analysis + class Analysis : IDisposable { readonly ILogger logger; @@ -71,12 +71,9 @@ namespace Semmle.Extraction.CSharp.Standalone projectExtraction.Sources.AddRange(options.SolutionFile == null ? buildAnalysis.AllSourceFiles : buildAnalysis.ProjectSourceFiles); } - /// - /// Delete any Nuget assemblies. - /// - public void Cleanup() + public void Dispose() { - buildAnalysis.Cleanup(); + buildAnalysis.Dispose(); } }; @@ -85,8 +82,9 @@ namespace Semmle.Extraction.CSharp.Standalone static int Main(string[] args) { var options = Options.Create(args); + // options.CIL = true; // To do: Enable this var output = new ConsoleLogger(options.Verbosity); - var a = new Analysis(output); + using var a = new Analysis(output); if (options.Help) { @@ -97,6 +95,8 @@ namespace Semmle.Extraction.CSharp.Standalone if (options.Errors) return 1; + var start = DateTime.Now; + output.Log(Severity.Info, "Running C# standalone extractor"); a.AnalyseProjects(options); int sourceFiles = a.Extraction.Sources.Count(); @@ -117,10 +117,9 @@ namespace Semmle.Extraction.CSharp.Standalone new ExtractionProgress(output), new FileLogger(options.Verbosity, Extractor.GetCSharpLogPath()), options); - output.Log(Severity.Info, "Extraction complete"); + output.Log(Severity.Info, $"Extraction completed in {DateTime.Now-start}"); } - a.Cleanup(); return 0; } @@ -151,7 +150,7 @@ namespace Semmle.Extraction.CSharp.Standalone public void MissingSummary(int missingTypes, int missingNamespaces) { - logger.Log(Severity.Info, "Failed to resolve {0} types and {1} namespaces", missingTypes, missingNamespaces); + logger.Log(Severity.Info, "Failed to resolve {0} types in {1} namespaces", missingTypes, missingNamespaces); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs index f4bde55ec55..5bbe1e3a5b2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/ProgressMonitor.cs @@ -1,4 +1,5 @@ using Semmle.Util.Logging; +using System; namespace Semmle.BuildAnalyser { @@ -9,15 +10,17 @@ namespace Semmle.BuildAnalyser { void FindingFiles(string dir); void UnresolvedReference(string id, string project); - void AnalysingProjectFiles(int count); + void AnalysingSolution(string filename); void FailedProjectFile(string filename, string reason); void FailedNugetCommand(string exe, string args, string message); void NugetInstall(string package); void ResolvedReference(string filename); - void Summary(int existingSources, int usedSources, int missingSources, int references, int unresolvedReferences, int resolvedConflicts, int totalProjects, int failedProjects); + void Summary(int existingSources, int usedSources, int missingSources, int references, int unresolvedReferences, int resolvedConflicts, int totalProjects, int failedProjects, TimeSpan analysisTime); void Warning(string message); void ResolvedConflict(string asm1, string asm2); void MissingProject(string projectFile); + void CommandFailed(string exe, string arguments, int exitCode); + void MissingNuGet(); } class ProgressMonitor : IProgressMonitor @@ -46,9 +49,9 @@ namespace Semmle.BuildAnalyser logger.Log(Severity.Debug, "Unresolved {0} referenced by {1}", id, project); } - public void AnalysingProjectFiles(int count) + public void AnalysingSolution(string filename) { - logger.Log(Severity.Info, "Analyzing project files..."); + logger.Log(Severity.Info, $"Analyzing {filename}..."); } public void FailedProjectFile(string filename, string reason) @@ -73,7 +76,9 @@ namespace Semmle.BuildAnalyser } public void Summary(int existingSources, int usedSources, int missingSources, - int references, int unresolvedReferences, int resolvedConflicts, int totalProjects, int failedProjects) + int references, int unresolvedReferences, + int resolvedConflicts, int totalProjects, int failedProjects, + TimeSpan analysisTime) { logger.Log(Severity.Info, ""); logger.Log(Severity.Info, "Build analysis summary:"); @@ -85,6 +90,7 @@ namespace Semmle.BuildAnalyser logger.Log(Severity.Info, "{0, 6} resolved assembly conflicts", resolvedConflicts); logger.Log(Severity.Info, "{0, 6} projects", totalProjects); logger.Log(Severity.Info, "{0, 6} missing/failed projects", failedProjects); + logger.Log(Severity.Info, "Build analysis completed in {0}", analysisTime); } public void Warning(string message) @@ -94,12 +100,22 @@ namespace Semmle.BuildAnalyser public void ResolvedConflict(string asm1, string asm2) { - logger.Log(Severity.Info, "Resolved {0} as {1}", asm1, asm2); + logger.Log(Severity.Debug, "Resolved {0} as {1}", asm1, asm2); } public void MissingProject(string projectFile) { logger.Log(Severity.Info, "Solution is missing {0}", projectFile); } + + public void CommandFailed(string exe, string arguments, int exitCode) + { + logger.Log(Severity.Error, $"Command {exe} {arguments} failed with exit code {exitCode}"); + } + + public void MissingNuGet() + { + logger.Log(Severity.Error, "Missing nuget.exe"); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj index 4cf0274b737..f9efd0d9ebb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj @@ -1,4 +1,4 @@ - + Exe @@ -14,6 +14,7 @@ + diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs index b1a3edd4cf6..b4551dd8024 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/SolutionFile.cs @@ -12,6 +12,8 @@ namespace Semmle.BuildAnalyser { readonly Microsoft.Build.Construction.SolutionFile solutionFile; + private string FullPath { get; } + /// /// Read the file. /// @@ -19,8 +21,8 @@ namespace Semmle.BuildAnalyser public SolutionFile(string filename) { // SolutionFile.Parse() expects a rooted path. - var fullPath = Path.GetFullPath(filename); - solutionFile = Microsoft.Build.Construction.SolutionFile.Parse(fullPath); + FullPath = Path.GetFullPath(filename); + solutionFile = Microsoft.Build.Construction.SolutionFile.Parse(FullPath); } /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index 0488fe84ffe..6962e8381d9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -45,7 +45,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Access(ExpressionNodeInfo info, ISymbol symbol, bool implicitThis, IEntity target) : base(info.SetKind(AccessKind(info.Context, symbol))) { - cx.TrapWriter.Writer.expr_access(this, target); + if (!(target is null)) + { + cx.TrapWriter.Writer.expr_access(this, target); + } if (implicitThis && !symbol.IsStatic) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs index e41ef0edf23..0bc84ca9c0c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs @@ -71,7 +71,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (symbol == null) { info.Context.ModelError(info.Node, "Failed to determine symbol for member access"); - return new MemberAccess(info.SetKind(ExprKind.UNKNOWN), expression, symbol); + // Default to property access - this can still give useful results but + // the target of the expression should be checked in QL. + return new MemberAccess(info.SetKind(ExprKind.PROPERTY_ACCESS), expression, symbol); } ExprKind kind; 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/NamespaceDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs index a0dd41aaafb..7a14bb719fc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs @@ -23,7 +23,8 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { - var ns = Namespace.Create(cx, (INamespaceSymbol)cx.GetModel(Node).GetSymbolInfo(Node.Name).Symbol); + var @namespace = (INamespaceSymbol) cx.GetModel(Node).GetSymbolInfo(Node.Name).Symbol; + var ns = Namespace.Create(cx, @namespace); trapFile.namespace_declarations(this, ns); trapFile.namespace_declaration_location(this, cx.Create(Node.Name.GetLocation())); 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 e22d32c0d01..93c13726750 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities { if (symbol.TypeKind == TypeKind.Error) { - Context.Extractor.MissingType(symbol.ToString()); + Context.Extractor.MissingType(symbol.ToString(), Context.FromSource); return; } @@ -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/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs index 4fdbe7c18ad..02b67efc164 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities if (namespaceSymbol == null) { - cx.Extractor.MissingNamespace(Node.Name.ToFullString()); + cx.Extractor.MissingNamespace(Node.Name.ToFullString(), cx.FromSource); cx.ModelError(Node, "Namespace not found"); return; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index c2cb6a367eb..6050ad910a5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -214,7 +214,6 @@ namespace Semmle.Extraction.CSharp static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action subTermAction) { bool prefixAssembly = true; - if (cx.Extractor.Standalone) prefixAssembly = false; if (named.ContainingAssembly is null) prefixAssembly = false; if (named.IsTupleType) 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 93f99381858..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; @@ -155,7 +182,7 @@ namespace Semmle.Extraction #if DEBUG_LABELS using (var id = new StringWriter()) { - entity.WriteId(id); + entity.WriteQuotedId(id); CheckEntityHasUniqueLabel(id.ToString(), entity); } #endif @@ -270,6 +297,8 @@ namespace Semmle.Extraction TrapWriter = trapWriter; } + public bool FromSource => Scope.FromSource; + public bool IsGlobalContext => Scope.IsGlobalScope; public readonly ICommentGenerator CommentGenerator = new CommentProcessor(); @@ -358,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) { @@ -451,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); @@ -465,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)) { @@ -537,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/ExtractionScope.cs b/csharp/extractor/Semmle.Extraction/ExtractionScope.cs index 7f4f599fe5c..60daff8d013 100644 --- a/csharp/extractor/Semmle.Extraction/ExtractionScope.cs +++ b/csharp/extractor/Semmle.Extraction/ExtractionScope.cs @@ -25,6 +25,8 @@ namespace Semmle.Extraction bool InFileScope(string path); bool IsGlobalScope { get; } + + bool FromSource { get; } } /// @@ -49,6 +51,8 @@ namespace Semmle.Extraction public bool InScope(ISymbol symbol) => SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, assembly) || SymbolEqualityComparer.Default.Equals(symbol, assembly); + + public bool FromSource => false; } /// @@ -68,5 +72,7 @@ namespace Semmle.Extraction public bool InFileScope(string path) => path == sourceTree.FilePath; public bool InScope(ISymbol symbol) => symbol.Locations.Any(loc => loc.SourceTree == sourceTree); + + public bool FromSource => true; } } diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index e470d3258ec..13750c1aa5c 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -50,13 +50,15 @@ namespace Semmle.Extraction /// Record a new error type. /// /// The display name of the type, qualified where possible. - void MissingType(string fqn); + /// If the missing type was referenced from a source file. + void MissingType(string fqn, bool fromSource); /// /// Record an unresolved `using namespace` directive. /// /// The full name of the namespace. - void MissingNamespace(string fqn); + /// If the missing namespace was referenced from a source file. + void MissingNamespace(string fqn, bool fromSource); /// /// The list of missing types. @@ -167,16 +169,22 @@ namespace Semmle.Extraction readonly ISet missingTypes = new SortedSet(); readonly ISet missingNamespaces = new SortedSet(); - public void MissingType(string fqn) + public void MissingType(string fqn, bool fromSource) { - lock (mutex) - missingTypes.Add(fqn); + if (fromSource) + { + lock (mutex) + missingTypes.Add(fqn); + } } - public void MissingNamespace(string fqdn) + public void MissingNamespace(string fqdn, bool fromSource) { - lock (mutex) - missingNamespaces.Add(fqdn); + if (fromSource) + { + lock (mutex) + missingNamespaces.Add(fqdn); + } } public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope) 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/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj index d0ef95a4d4c..a82997aea63 100644 --- a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj +++ b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj @@ -5,6 +5,7 @@ netcoreapp3.0 false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Util/ActionMap.cs b/csharp/extractor/Semmle.Util/ActionMap.cs index 019410be7b2..c9fecbf9da6 100644 --- a/csharp/extractor/Semmle.Util/ActionMap.cs +++ b/csharp/extractor/Semmle.Util/ActionMap.cs @@ -9,20 +9,19 @@ namespace Semmle.Util /// /// /// - public class ActionMap + public class ActionMap where Key : notnull { public void Add(Key key, Value value) { - Action a; - if (actions.TryGetValue(key, out a)) + + if (actions.TryGetValue(key, out var a)) a(value); values[key] = value; } public void OnAdd(Key key, Action action) { - Action a; - if (actions.TryGetValue(key, out a)) + if (actions.TryGetValue(key, out var a)) { actions[key] = a + action; } diff --git a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs index 3610bb0d46e..bbc8ab995b4 100644 --- a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs @@ -127,8 +127,8 @@ namespace Semmle.Util if (parent != null) { - string name = Path.GetFileName(path); - string parentPath = cache.GetCanonicalPath(parent.FullName); + var name = Path.GetFileName(path); + var parentPath = cache.GetCanonicalPath(parent.FullName); try { string[] entries = Directory.GetFileSystemEntries(parentPath, name); @@ -313,14 +313,15 @@ namespace Semmle.Util /// The canonical path. public string GetCanonicalPath(string path) { - string canonicalPath; lock (cache) - if (!cache.TryGetValue(path, out canonicalPath)) + { + if (!cache.TryGetValue(path, out var canonicalPath)) { canonicalPath = pathStrategy.GetCanonicalPath(path, this); AddToCache(path, canonicalPath); } - return canonicalPath; + return canonicalPath; + } } } } diff --git a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs index b7c5166f2f0..01a581d612d 100644 --- a/csharp/extractor/Semmle.Util/CommandLineExtensions.cs +++ b/csharp/extractor/Semmle.Util/CommandLineExtensions.cs @@ -18,7 +18,7 @@ namespace Semmle.Util var found = false; foreach (var arg in commandLineArguments.Where(arg => arg.StartsWith('@')).Select(arg => arg.Substring(1))) { - string line; + string? line; using (StreamReader file = new StreamReader(arg)) while ((line = file.ReadLine()) != null) textWriter.WriteLine(line); diff --git a/csharp/extractor/Semmle.Util/DictionaryExtensions.cs b/csharp/extractor/Semmle.Util/DictionaryExtensions.cs index 7a15ce10c92..bb0d732a17f 100644 --- a/csharp/extractor/Semmle.Util/DictionaryExtensions.cs +++ b/csharp/extractor/Semmle.Util/DictionaryExtensions.cs @@ -9,10 +9,9 @@ namespace Semmle.Util /// dictionary. If a list does not already exist, a new list is /// created. /// - public static void AddAnother(this Dictionary> dict, T1 key, T2 element) + public static void AddAnother(this Dictionary> dict, T1 key, T2 element) where T1:notnull { - List list; - if (!dict.TryGetValue(key, out list)) + if (!dict.TryGetValue(key, out var list)) { list = new List(); dict[key] = list; diff --git a/csharp/extractor/Semmle.Util/FileRenamer.cs b/csharp/extractor/Semmle.Util/FileRenamer.cs new file mode 100644 index 00000000000..ad5001f7e13 --- /dev/null +++ b/csharp/extractor/Semmle.Util/FileRenamer.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Semmle.Util +{ + /// + /// Utility to temporarily rename a set of files. + /// + public sealed class FileRenamer : IDisposable + { + readonly string[] files; + const string suffix = ".codeqlhidden"; + + public FileRenamer(IEnumerable oldFiles) + { + files = oldFiles.Select(f => f.FullName).ToArray(); + + foreach (var file in files) + { + File.Move(file, file + suffix); + } + } + + public void Dispose() + { + foreach (var file in files) + { + File.Move(file + suffix, file); + } + } + } +} diff --git a/csharp/extractor/Semmle.Util/FileUtils.cs b/csharp/extractor/Semmle.Util/FileUtils.cs index e5f10a18521..32e2ed88e60 100644 --- a/csharp/extractor/Semmle.Util/FileUtils.cs +++ b/csharp/extractor/Semmle.Util/FileUtils.cs @@ -62,7 +62,7 @@ namespace Semmle.Util /// /// Returns null of no path can be found. /// - public static string FindProgramOnPath(string prog) + public static string? FindProgramOnPath(string prog) { var paths = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator); string[] exes; diff --git a/csharp/extractor/Semmle.Util/FuzzyDictionary.cs b/csharp/extractor/Semmle.Util/FuzzyDictionary.cs index a00d75fbbe5..6f364904b06 100644 --- a/csharp/extractor/Semmle.Util/FuzzyDictionary.cs +++ b/csharp/extractor/Semmle.Util/FuzzyDictionary.cs @@ -37,7 +37,7 @@ namespace Semmle.Util /// /// /// The value type. - public class FuzzyDictionary + public class FuzzyDictionary where T:class { // All data items indexed by the "base string" (stripped of numbers) readonly Dictionary>> index = new Dictionary>>(); @@ -61,7 +61,7 @@ namespace Semmle.Util /// Vector 1 /// Vector 2 /// The Hamming Distance. - static int HammingDistance(IEnumerable v1, IEnumerable v2) + static int HammingDistance(IEnumerable v1, IEnumerable v2) where U: notnull { return v1.Zip(v2, (x, y) => x.Equals(y) ? 0 : 1).Sum(); } @@ -72,11 +72,10 @@ namespace Semmle.Util /// The query string. /// The distance between the query string and the stored string. /// The best match, or null (default). - public T FindMatch(string query, out int distance) + public T? FindMatch(string query, out int distance) { string root = StripDigits(query); - List> list; - if (!index.TryGetValue(root, out list)) + if (!index.TryGetValue(root, out var list)) { distance = 0; return default(T); @@ -93,9 +92,9 @@ namespace Semmle.Util /// The distance function. /// The distance between the query and the stored string. /// The stored value. - static T BestMatch(string query, IEnumerable> candidates, Func distance, out int bestDistance) + static T? BestMatch(string query, IEnumerable> candidates, Func distance, out int bestDistance) { - T bestMatch = default(T); + T? bestMatch = default(T); bestDistance = 0; bool first = true; diff --git a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs index d53fcf99ff4..7665dedfa70 100644 --- a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs +++ b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs @@ -93,7 +93,7 @@ namespace Semmle.Util /// The type of the item. /// The list of items to hash. /// The hash code. - public static int SequenceHash(this IEnumerable items) + public static int SequenceHash(this IEnumerable items) where T: notnull { int h = 0; foreach (var i in items) diff --git a/csharp/extractor/Semmle.Util/LineCounter.cs b/csharp/extractor/Semmle.Util/LineCounter.cs index c122d5865be..f4f6758a250 100644 --- a/csharp/extractor/Semmle.Util/LineCounter.cs +++ b/csharp/extractor/Semmle.Util/LineCounter.cs @@ -31,9 +31,9 @@ namespace Semmle.Util //#################### PUBLIC METHODS #################### #region - public override bool Equals(Object other) + public override bool Equals(object? other) { - LineCounts rhs = other as LineCounts; + var rhs = other as LineCounts; return rhs != null && Total == rhs.Total && Code == rhs.Code && Comment == rhs.Comment; } diff --git a/csharp/extractor/Semmle.Util/Logger.cs b/csharp/extractor/Semmle.Util/Logger.cs index d6405724734..cd353bd4f0f 100644 --- a/csharp/extractor/Semmle.Util/Logger.cs +++ b/csharp/extractor/Semmle.Util/Logger.cs @@ -67,8 +67,8 @@ namespace Semmle.Util.Logging try { - var dir = Path.GetDirectoryName(outputFile); - if (dir.Length > 0 && !System.IO.Directory.Exists(dir)) + string? dir = Path.GetDirectoryName(outputFile); + if (!string.IsNullOrEmpty(dir) && !System.IO.Directory.Exists(dir)) Directory.CreateDirectory(dir); writer = new PidStreamWriter(new FileStream(outputFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 8192)); diff --git a/csharp/extractor/Semmle.Util/LoggerUtils.cs b/csharp/extractor/Semmle.Util/LoggerUtils.cs index 39a40c37158..d94ff6f189f 100644 --- a/csharp/extractor/Semmle.Util/LoggerUtils.cs +++ b/csharp/extractor/Semmle.Util/LoggerUtils.cs @@ -21,7 +21,7 @@ namespace Semmle.Util private readonly string prefix = "[" + Process.GetCurrentProcess().Id + "] "; - public override void WriteLine(string value) + public override void WriteLine(string? value) { lock (mutex) { @@ -29,9 +29,9 @@ namespace Semmle.Util } } - public override void WriteLine(string value, object[] args) + public override void WriteLine(string? value, object?[] args) { - WriteLine(String.Format(value, args)); + WriteLine(value is null ? value : String.Format(value, args)); } readonly object mutex = new object(); diff --git a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs index 0d9d6b04a13..5252372a58b 100644 --- a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs +++ b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs @@ -14,7 +14,7 @@ namespace Semmle.Util stdout = new List(); using (var process = Process.Start(pi)) { - string s; + string? s; do { s = process.StandardOutput.ReadLine(); diff --git a/csharp/extractor/Semmle.Util/Semmle.Util.csproj b/csharp/extractor/Semmle.Util/Semmle.Util.csproj index 4ef3eda35d9..39f0c7cdedb 100644 --- a/csharp/extractor/Semmle.Util/Semmle.Util.csproj +++ b/csharp/extractor/Semmle.Util/Semmle.Util.csproj @@ -6,6 +6,7 @@ Semmle.Util false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Util/SharedReference.cs b/csharp/extractor/Semmle.Util/SharedReference.cs index 6870c5acb35..ba87caeefaa 100644 --- a/csharp/extractor/Semmle.Util/SharedReference.cs +++ b/csharp/extractor/Semmle.Util/SharedReference.cs @@ -13,6 +13,6 @@ namespace Semmle.Util /// /// The shared object to which different parts of the code want to refer. /// - public T Obj { get; set; } + public T? Obj { get; set; } } } diff --git a/csharp/extractor/Semmle.Util/TemporaryDirectory.cs b/csharp/extractor/Semmle.Util/TemporaryDirectory.cs new file mode 100644 index 00000000000..a155372c9d8 --- /dev/null +++ b/csharp/extractor/Semmle.Util/TemporaryDirectory.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Semmle.Util +{ + /// + /// A temporary directory that is created within the system temp directory. + /// When this object is disposed, the directory is deleted. + /// + public sealed class TemporaryDirectory : IDisposable + { + public DirectoryInfo DirInfo { get; } + + public TemporaryDirectory(string name) + { + DirInfo = new DirectoryInfo(name); + DirInfo.Create(); + } + + public void Dispose() + { + DirInfo.Delete(true); + } + + public override string ToString() => DirInfo.FullName.ToString(); + } +} 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/qlpack.yml b/csharp/ql/src/qlpack.yml index df14eec51a7..6bb4774c070 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-csharp version: 0.0.0 dbscheme: semmlecode.csharp.dbscheme suites: codeql-suites +extractor: csharp 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/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 79481a8c63d..02b0125a421 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() @@ -350,15 +348,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/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 8a6fdafc903..bfd7487f82f 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -1710,9 +1710,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 +1725,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 +1739,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/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..fdf0480c8ef 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -346,11 +346,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..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..852f54974e2 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,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - 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. * * `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 any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) 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() - ) - 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()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) 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, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, 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, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) 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, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * 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). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - 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, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `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). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - 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, contentIn) 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(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ 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) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ 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 TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,8 +415,7 @@ 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 } } @@ -538,7 +423,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -678,6 +563,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 +585,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 +597,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 +611,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 +678,58 @@ 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())) + } +} + +/** + * 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(Content f) { this = TFrontHead(f) } +} + +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 } +} + +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 } +} + +/** 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..f9bac316d70 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -81,9 +81,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 +241,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 +259,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 +372,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 +386,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 +406,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 +441,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 +476,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 +505,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 +527,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. @@ -607,44 +626,6 @@ private module ParameterNodes { override string toString() { result = "this" } } - /** - * 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() } - } - module ImplicitCapturedParameterNodeImpl { /** An implicit entry definition for a captured variable. */ class SsaCapturedEntryDefinition extends Ssa::ImplicitEntryDefinition { @@ -688,7 +669,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 +722,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 +741,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 +757,6 @@ private module ArgumentNodes { c = call.getExpr() and arg = c.getArgument(pos) ) - or - flowIntoCallableLibraryCall(this, call, pos) } } @@ -833,7 +767,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; } @@ -913,6 +847,43 @@ private module ArgumentNodes { override string toString() { 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, 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 getEnclosingCallable() { result = cfn.getEnclosingCallable() } + + override Type getType() { + result = this.getDelegateCall().getDelegateParameterType(parameterIndex) + } + + override Location getLocation() { result = cfn.getLocation() } + + override string toString() { result = "[implicit argument " + parameterIndex + "] " + cfn } + } } import ArgumentNodes @@ -964,31 +935,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, PostUpdateNode, 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 ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn } - override Type getType() { - result = this.getUnderlyingNode().getEnclosingCallable().getReturnType() - } + override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() } - override Location getLocation() { result = this.getUnderlyingNode().getLocation() } + override Type getType() { result = yrs.getEnclosingCallable().getReturnType() } - override string toString() { result = this.getUnderlyingNode().toString() } + override Location getLocation() { result = yrs.getLocation() } + + override string toString() { result = yrs.toString() } } /** @@ -998,7 +967,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) { @@ -1188,68 +1157,290 @@ private module OutNodes { 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 Node, 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 getEnclosingCallable() { result = callCfn.getEnclosingCallable() } + + override DataFlowType getTypeBound() { + preservesValue = true and + sourceAp = AccessPath::empty() and + result = this.getPredecessor(_).getTypeBound() + or + result = sourceAp.getHead().getType() + or + preservesValue = false and + result = this.getSuccessor(_).getTypeBound() + } + + override Location getLocation() { result = callCfn.getLocation() } + + override string toString() { 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 +1452,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 +1509,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 +1517,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 +1536,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration ) { exactScope = false and isSuccessor = true and - e1 = e2.(FieldLikeRead).getQualifier() and + fieldOrPropertyRead(e1, _, e2) and scope = e2 } } @@ -1432,7 +1600,7 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } } - private class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { private ControlFlow::Nodes::ElementNode cfn; ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) } @@ -1508,3 +1676,6 @@ int accessPathLimit() { result = 3 } * This predicate is only used for consistency checks. */ predicate isImmutableOrUnobservable(Node n) { none() } + +pragma[inline] +DataFlowType getErasedRepr(DataFlowType t) { result = t } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index d5dff3b8b21..328db073d6e 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 @@ -40,8 +41,17 @@ class Node extends TNode { cached DotNet::Type getType() { none() } - /** 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 @@ -136,8 +146,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 +240,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. */ + DataFlowType getContainerType() { none() } + + /** Gets the type of this content. */ + 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() } + + override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(f.getDeclaringType()) + } + + 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() } + + override DataFlowType getContainerType() { + result = Gvn::getGlobalValueNumber(p.getDeclaringType()) + } + + 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..93fe29c4619 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,7 @@ 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 = nodeTo.(YieldReturnNode).getPreUpdateNode() or localTaintStepCil(nodeFrom, nodeTo) or @@ -180,7 +173,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/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index c0d75bfd9fe..842c374ecd1 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -388,7 +388,12 @@ library class PropertyAccessExpr extends Expr, @property_access_expr { /** Gets the target of this property access. */ Property getProperty() { expr_access(this, result) } - override string toString() { result = "access to property " + this.getProperty().getName() } + override string toString() { + result = "access to property " + this.getProperty().getName() + or + not exists(this.getProperty()) and + result = "access to property (unknown)" + } } /** @@ -561,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() } } /** @@ -581,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 @@ -813,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 @@ -825,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/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/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 833c929ecc5..9a75ca19154 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/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,7 +106,7 @@ 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) @@ -133,7 +135,7 @@ class IRNumericType extends IRSizedType { IRNumericType() { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) or - this = TIRFloatingPointType(byteSize) + this = TIRFloatingPointType(byteSize, _, _) } } @@ -171,14 +173,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" + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll index 49cb4dd6dc4..dce1717bdc9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll @@ -101,23 +101,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 +130,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/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll index 94d0192fe18..edf4bc00259 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll @@ -149,6 +149,26 @@ module InstructionSanity { count(instr.getBlock().getAPredecessor()) < 2 } + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + /** * Holds if operand `operand` consumes a value that was defined in * a different function. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index fc9d0758125..780f636ff10 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -190,14 +190,15 @@ 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) } /** - * 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) @@ -525,7 +526,7 @@ class ReturnValueInstruction extends ReturnInstruction { final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } -class ReturnIndirectionInstruction extends Instruction { +class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -535,6 +536,12 @@ class ReturnIndirectionInstruction extends Instruction { final AddressOperand getSourceAddressOperand() { result = getAnOperand() } final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + /** + * Gets the parameter for which this instruction reads the final pointed-to value within the + * function. + */ + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } class CopyInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll index 49cb4dd6dc4..dce1717bdc9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -101,23 +101,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 +130,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/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll index 94d0192fe18..edf4bc00259 100644 --- 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 @@ -149,6 +149,26 @@ module InstructionSanity { count(instr.getBlock().getAPredecessor()) < 2 } + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + /** * Holds if operand `operand` consumes a value that was defined in * a different function. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index fc9d0758125..780f636ff10 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -190,14 +190,15 @@ 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) } /** - * 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) @@ -525,7 +526,7 @@ class ReturnValueInstruction extends ReturnInstruction { final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } -class ReturnIndirectionInstruction extends Instruction { +class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -535,6 +536,12 @@ class ReturnIndirectionInstruction extends Instruction { final AddressOperand getSourceAddressOperand() { result = getAnOperand() } final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } + + /** + * Gets the parameter for which this instruction reads the final pointed-to value within the + * function. + */ + final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } class CopyInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/semmle/code/csharp/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/semmle/code/csharp/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/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll index cffe3d09f39..fdd7ef804d2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -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)) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll index a8fb448f8d0..2272257fb19 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll +++ b/csharp/ql/src/semmle/code/csharp/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/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/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index f0a19c633d7..a6baeb18564 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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 5db89e6d2ca..a4fda4ea940 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 | @@ -4515,6 +4533,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 | @@ -6943,6 +6979,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 ...) ... | @@ -8747,6 +8790,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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index d6c78dda8ae..0619257c9ed 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 | @@ -3548,6 +3568,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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 29ef1c6475b..9b9bfec2d27 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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index 622637f5c9d..6d20b0e2271 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 | 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/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 4756e86100b..256f8d8ad36 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 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index 0a7201f1280..2974031c5db 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -710,6 +710,7 @@ 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 | {...} | 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/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..a46026ba3da 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -75,7 +75,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 +84,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 +100,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 +149,41 @@ 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 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs: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:39:189:41 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | | 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 | @@ -300,46 +303,49 @@ 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:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs: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 +374,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 +396,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..c0422a5f0f5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -75,7 +75,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 +84,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 +100,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 +140,33 @@ 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:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | +| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | +| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | @@ -173,58 +179,61 @@ 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 | [library code] object creation of type Lazy : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | +| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs: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:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | +| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | +| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | +| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | +| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:211:71:211:71 | x : String | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | +| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | +| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | | 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 | @@ -333,22 +342,28 @@ 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:82:76:82:86 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84: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:84:117:84:127 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:86:70:86: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:86:117:86:127 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | -| GlobalDataFlow.cs:88: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:88:83:88:101 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | +| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90: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:90:83:90:101 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | +| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | @@ -371,68 +386,71 @@ 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:22:189:42 | [library code] object creation of type Lazy : String | semmle.label | [library code] object creation of type Lazy : String | +| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy [Value] : String | semmle.label | object creation of type Lazy [Value] : String | +| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs: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:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | semmle.label | [implicit argument 0] access to local variable f1 : String | +| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | +| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | semmle.label | [implicit argument 0] access to local variable f2 : String | +| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | +| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func : String | semmle.label | [implicit argument 0] delegate creation of type Func : String | +| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func : String | semmle.label | [output] delegate creation of type Func : String | +| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable | semmle.label | yield return ...; : IEnumerable | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | | 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 +503,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..92f60ec551e 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -114,6 +114,18 @@ 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; } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 40e9c750a12..15dd073b91d 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -39,6 +39,10 @@ edges | 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:120:25:120:31 | object creation of type A : A | Types.cs:122:30:122:30 | access to local variable a : A | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:30:123:31 | access to local variable e2 : E2 | +| Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : E2 | Types.cs:123:22:123:32 | call to method Through | 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 | @@ -90,6 +94,12 @@ nodes | 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:115:22:115:31 | access to field Field | semmle.label | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | semmle.label | object creation of type A : A | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | semmle.label | object creation of type E2 : E2 | +| Types.cs:122:22:122:31 | call to method Through | semmle.label | call to method Through | +| Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | +| Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : E2 | semmle.label | access to local variable e2 : E2 | #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 | (...) ... | (...) ... | @@ -106,3 +116,5 @@ nodes | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | | Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | 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_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected index c5a0b98598f..61bc9b2261c 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges 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 index c5a0b98598f..61bc9b2261c 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -9,6 +9,7 @@ instructionWithoutSuccessor ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction +memoryOperandDefinitionIsUnmodeled operandAcrossFunctions instructionWithoutUniqueBlock containsLoopOfForwardEdges diff --git a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected index 06473196df9..a9eb533c152 100644 --- a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected +++ b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected @@ -7,9 +7,14 @@ | ControlFlow.cs:10:9:10:43 | Call (unknown target) | ControlFlow.cs:12:9:12:87 | ...; | | ControlFlow.cs:10:9:10:43 | call to method | ControlFlow.cs:12:9:12:87 | ...; | | ControlFlow.cs:10:9:10:44 | ...; | ControlFlow.cs:10:9:10:13 | Expression | -| ControlFlow.cs:10:22:10:22 | access to local variable v | ControlFlow.cs:10:22:10:24 | Expression | -| ControlFlow.cs:10:22:10:24 | Expression | ControlFlow.cs:10:22:10:26 | Expression | -| ControlFlow.cs:10:22:10:26 | Expression | ControlFlow.cs:10:29:10:42 | "This is true" | +| ControlFlow.cs:10:22:10:22 | access to local variable v | ControlFlow.cs:10:22:10:24 | Call (unknown target) | +| ControlFlow.cs:10:22:10:22 | access to local variable v | ControlFlow.cs:10:22:10:24 | access to property (unknown) | +| ControlFlow.cs:10:22:10:24 | Call (unknown target) | ControlFlow.cs:10:22:10:26 | Call (unknown target) | +| ControlFlow.cs:10:22:10:24 | Call (unknown target) | ControlFlow.cs:10:22:10:26 | access to property (unknown) | +| ControlFlow.cs:10:22:10:24 | access to property (unknown) | ControlFlow.cs:10:22:10:26 | Call (unknown target) | +| ControlFlow.cs:10:22:10:24 | access to property (unknown) | ControlFlow.cs:10:22:10:26 | access to property (unknown) | +| ControlFlow.cs:10:22:10:26 | Call (unknown target) | ControlFlow.cs:10:29:10:42 | "This is true" | +| 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 | @@ -20,5 +25,7 @@ | 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 | Expression | -| ControlFlow.cs:12:79:12:84 | Expression | ControlFlow.cs:12:65:12:84 | ... = ... | +| 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) | +| ControlFlow.cs:12:79:12:84 | Call (unknown target) | ControlFlow.cs:12:65:12:84 | ... = ... | +| ControlFlow.cs:12:79:12:84 | access to property (unknown) | ControlFlow.cs:12:65:12:84 | ... = ... | diff --git a/csharp/ql/test/library-tests/standalone/errorrecovery/ErrorCalls.expected b/csharp/ql/test/library-tests/standalone/errorrecovery/ErrorCalls.expected index 05ae24318c3..d57c3c86bbd 100644 --- a/csharp/ql/test/library-tests/standalone/errorrecovery/ErrorCalls.expected +++ b/csharp/ql/test/library-tests/standalone/errorrecovery/ErrorCalls.expected @@ -2,5 +2,5 @@ | errors.cs:43:21:43:28 | errors.cs:43:21:43:28 | object creation of type C1 | C1 | | errors.cs:44:13:44:19 | errors.cs:44:13:44:19 | call to method m1 | m1 | | errors.cs:45:13:45:19 | errors.cs:45:13:45:19 | call to method m2 | m2 | -| errors.cs:46:13:46:38 | errors.cs:46:13:46:38 | call to method | none | +| errors.cs:46:13:46:38 | errors.cs:46:13:46:38 | call to method WriteLine | WriteLine | | errors.cs:53:17:53:25 | errors.cs:53:17:53:25 | object creation of type C2 | none | diff --git a/csharp/ql/test/library-tests/standalone/regressions/ConstCase.expected b/csharp/ql/test/library-tests/standalone/regressions/ConstCase.expected index 47045b907f6..2c8616d347a 100644 --- a/csharp/ql/test/library-tests/standalone/regressions/ConstCase.expected +++ b/csharp/ql/test/library-tests/standalone/regressions/ConstCase.expected @@ -1,2 +1,3 @@ -| regressions.cs:16:13:16:37 | case ...: | regressions.cs:16:18:16:36 | Expression | -| regressions.cs:18:13:18:37 | case ...: | regressions.cs:18:18:18:36 | Expression | +| regressions.cs:16:13:16:37 | case ...: | regressions.cs:16:18:16:36 | access to property (unknown) | +| regressions.cs:18:13:18:37 | case ...: | regressions.cs:18:18:18:36 | access to property (unknown) | +| regressions.cs:20:13:20:23 | case ...: | regressions.cs:20:18:20:22 | Int32 x | diff --git a/csharp/ql/test/library-tests/standalone/regressions/ConstCase.ql b/csharp/ql/test/library-tests/standalone/regressions/ConstCase.ql index 7ee7754e91e..6c5d54518fe 100644 --- a/csharp/ql/test/library-tests/standalone/regressions/ConstCase.ql +++ b/csharp/ql/test/library-tests/standalone/regressions/ConstCase.ql @@ -1,7 +1,5 @@ import csharp from Case c, Expr e -where - e = c.getPattern().stripCasts() and - (e instanceof @unknown_expr or e instanceof ConstantPatternExpr) +where e = c.getPattern().stripCasts() select c, e diff --git a/csharp/ql/test/qlpack.yml b/csharp/ql/test/qlpack.yml index 20f6e83ee30..2b8cce91f07 100644 --- a/csharp/ql/test/qlpack.yml +++ b/csharp/ql/test/qlpack.yml @@ -1,3 +1,4 @@ name: codeql-csharp-tests version: 0.0.0 libraryPathDependencies: codeql-csharp +extractor: csharp 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..2436335932e 100644 --- a/docs/language/README.rst +++ b/docs/language/README.rst @@ -104,12 +104,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/fire-1.rst b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst similarity index 73% rename from docs/language/learn-ql/beginner/fire-1.rst rename to docs/language/learn-ql/beginner/catch-the-fire-starter.rst index d5427b56d5f..72f3f4f7685 100644 --- a/docs/language/learn-ql/beginner/fire-1.rst +++ b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst @@ -1,5 +1,7 @@ -Catch the fire starter: Classes and predicates -============================================== +Catch the fire starter +====================== + +Learn about QL predicates and classes to solve your second mystery as a QL detective. Just as you've successfully found the thief and returned the golden crown to the castle, another terrible crime is committed. Early in the morning, a few people start a fire in a field in the north of the village and destroy all the crops! @@ -101,6 +103,50 @@ Now try applying ``isAllowedIn(string region)`` to a person ``p``. If ``p`` is n You know that the fire starters live in the south *and* that they must have been able to travel to the north. Write a query to find the possible suspects. You could also extend the ``select`` clause to list the age of the suspects. That way you can clearly see that all the children have been excluded from the list. -➤ `See the answer in the query console `__ +➤ `See the answer in the query console on LGTM.com `__ -Continue to the :doc:`next page ` to gather more clues and find out which of your suspects started the fire... +You can now continue to gather more clues and find out which of your suspects started the fire... + +Identify the bald bandits +------------------------- + +You ask the northerners if they have any more information about the fire starters. Luckily, you have a witness! The farmer living next to the field saw two people run away just after the fire started. He only saw the tops of their heads, and noticed that they were both bald. + +This is a very helpful clue. Remember that you wrote a QL query to select all bald people: + +.. code-block:: ql + + from Person p + where not exists (string c | p.getHairColor() = c) + select p + +To avoid having to type ``not exists (string c | p.getHairColor() = c)`` every time you want to select a bald person, you can instead define another new predicate ``isBald``. + +.. code-block:: ql + + predicate isBald(Person p) { + not exists (string c | p.getHairColor() = c) + } + +The property ``isBald(p)`` holds whenever ``p`` is bald, so you can replace the previous query with: + +.. code-block:: ql + + from Person p + where isBald(p) + select p + +The predicate ``isBald`` is defined to take a ``Person``, so it can also take a ``Southerner``, as ``Southerner`` is a subtype of ``Person``. It can't take an ``int`` for example—that would cause an error. + +You can now write a query to select the bald southerners who are allowed into the north. + +➤ `See the answer in the query console on LGTM.com `__ + +You have found the two fire starters! They are arrested and the villagers are once again impressed with your work. + +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>`. diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.rst b/docs/language/learn-ql/beginner/cross-the-river.rst similarity index 95% rename from docs/language/learn-ql/ql-etudes/river-crossing.rst rename to docs/language/learn-ql/beginner/cross-the-river.rst index fef3363a08b..3f5307d98d5 100644 --- a/docs/language/learn-ql/ql-etudes/river-crossing.rst +++ b/docs/language/learn-ql/beginner/cross-the-river.rst @@ -1,7 +1,10 @@ -River crossing puzzle -##################### +Cross the river +=============== -The aim of this tutorial is to write a query that finds a solution to the following classical logic puzzle: +Use common QL features to write a query that finds a solution to the "River crossing" logic puzzle. + +Introduction +------------ .. pull-quote:: @@ -248,15 +251,15 @@ Here are some more example queries that solve the river crossing puzzle: #. This query uses a modified ``path`` variable to describe the resulting path in more detail. - ➤ `See solution in the query console `__ + ➤ `See solution in the query console on LGTM.com `__ #. This query models the man and the cargo items in a different way, using an `abstract `__ class and predicate. It also displays the resulting path in a more visual way. - ➤ `See solution in the query console `__ + ➤ `See solution in the query console on LGTM.com `__ #. This query introduces `algebraic datatypes `__ to model the situation, instead of defining everything as a subclass of ``string``. - ➤ `See solution in the query console `__ \ No newline at end of file + ➤ `See solution in the query console on LGTM.com `__ \ No newline at end of file diff --git a/docs/language/learn-ql/beginner/heir.rst b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst similarity index 93% rename from docs/language/learn-ql/beginner/heir.rst rename to docs/language/learn-ql/beginner/crown-the-rightful-heir.rst index 42589f03125..df3cd61fde9 100644 --- a/docs/language/learn-ql/beginner/heir.rst +++ b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst @@ -1,6 +1,11 @@ Crown the rightful heir ======================= +This is a QL detective puzzle that shows you how to use recursion in QL to write more complex queries. + +King Basil's heir +----------------- + Phew! No more crimes in the village—you can finally leave the village and go home. But then... During your last night in the village, the old king—the great King Basil—dies in his sleep and there is chaos everywhere! @@ -9,9 +14,6 @@ The king never married and he had no children, so nobody knows who should inheri Eventually you decide to stay in the village to resolve the argument and find the true heir to the throne. -King Basil's heir ------------------ - You want to find out if anyone in the village is actually related to the king. This seems like a difficult task at first, but you start work confidently. You know the villagers quite well by now, and you have a list of all the parents in the village and their children. To find out more about the king and his family, you get access to the castle and find some old family trees. You also include these relations in your database to see if anyone in the king's family is still alive. @@ -125,7 +127,7 @@ Here is one way to define ``relativeOf()``: Don't forget to use the predicate ``isDeceased()`` to find relatives that are still alive. -➤ `See the answer in the query console `__ +➤ `See the answer in the query console on LGTM.com `__ Select the true heir -------------------- @@ -136,9 +138,9 @@ To decide who should inherit the king's fortune, the villagers carefully read th *"The heir to the throne is the closest living relative of the king. Any person with a criminal record will not be considered. If there are multiple candidates, the oldest person is the heir."* -As your final challenge, define a predicate ``hasCriminalRecord`` so that ``hasCriminalRecord(p)`` holds if ``p`` is any of the criminals you unmasked earlier (in the :doc:`Find the thief ` and :doc:`Catch the fire starter ` tutorials). +As your final challenge, define a predicate ``hasCriminalRecord`` so that ``hasCriminalRecord(p)`` holds if ``p`` is any of the criminals you unmasked earlier (in the :doc:`Find the thief ` and :doc:`Catch the fire starter ` tutorials). -➤ `See the answer in the query console `__ +➤ `See the answer in the query console on LGTM.com `__ Experimental explorations ------------------------- @@ -156,9 +158,9 @@ You could also try writing more of your own QL queries to find interesting facts - Do all villagers live in the same region of the village as their parents? - Find out whether there are any time travelers in the village! (Hint: Look for "impossible" family relations.) -What next? ----------- +Further reading +--------------- -- Learn more about recursion in the `QL language handbook `__. -- Put your QL skills to the test and solve the :doc:`River crossing puzzle <../ql-etudes/river-crossing>`. +- 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. diff --git a/docs/language/learn-ql/beginner/find-the-thief.rst b/docs/language/learn-ql/beginner/find-the-thief.rst new file mode 100644 index 00000000000..02f19cce325 --- /dev/null +++ b/docs/language/learn-ql/beginner/find-the-thief.rst @@ -0,0 +1,297 @@ +Find the thief +============== + +Take on the role of a detective to find the thief in this fictional village. You will learn how to use logical connectives, quantifiers, and aggregates in QL along the way. + +Introduction +------------ + +There is a small village hidden away in the mountains. The village is divided into four parts—north, south, east, and west—and in the center stands a dark and mysterious castle... Inside the castle, locked away in the highest tower, lies the king's valuable golden crown. One night, a terrible crime is committed. A thief breaks into the tower and steals the crown! + +You know that the thief must live in the village, since nobody else knew about the crown. After some expert detective work, you obtain a list of all the people in the village and some of their personal details. + ++------+-----+------------+--------+----------+ +| Name | Age | Hair color | Height | Location | ++======+=====+============+========+==========+ +| ... | ... | ... | ... | ... | ++------+-----+------------+--------+----------+ + +Sadly, you still have no idea who could have stolen the crown so you walk around the village to find clues. The villagers act very suspiciously and you are convinced they have information about the thief. They refuse to share their knowledge with you directly, but they reluctantly agree to answer questions. They are still not very talkative and **only answer questions with 'yes' or 'no'**. + +You start asking some creative questions and making notes of the answers so you can compare them with your information later: + ++------+--------------------------------------------------------------------+--------+ +| | Question | Answer | ++======+====================================================================+========+ +| (1) | Is the thief taller than 150 cm? | yes | ++------+--------------------------------------------------------------------+--------+ +| (2) | Does the thief have blond hair? | no | ++------+--------------------------------------------------------------------+--------+ +| (3) | Is the thief bald? | no | ++------+--------------------------------------------------------------------+--------+ +| (4) | Is the thief younger than 30? | no | ++------+--------------------------------------------------------------------+--------+ +| (5) | Does the thief live east of the castle? | yes | ++------+--------------------------------------------------------------------+--------+ +| (6) | Does the thief have black or brown hair? | yes | ++------+--------------------------------------------------------------------+--------+ +| (7) | Is the thief taller than 180cm and shorter than 190cm? | no | ++------+--------------------------------------------------------------------+--------+ +| (8) | Is the thief the tallest person in the village? | no | ++------+--------------------------------------------------------------------+--------+ +| (9) | Is the thief shorter than the average villager? | yes | ++------+--------------------------------------------------------------------+--------+ +| (10) | Is the thief the oldest person in the eastern part of the village? | yes | ++------+--------------------------------------------------------------------+--------+ + +There is too much information to search through by hand, so you decide to use your newly acquired QL skills to help you with your investigation... + +#. Open the `query console on LGTM.com `__ to get started. +#. Select a language and a demo project. For this tutorial, any language and project will do. +#. Delete the default code ``import select "hello world"``. + +QL libraries +------------ + +We've defined a number of QL `predicates `__ to help you extract data from your table. A QL predicate is a mini-query that expresses a relation between various pieces of data and describes some of their properties. In this case, the predicates give you information about a person, for example their height or age. + ++--------------------+----------------------------------------------------------------------------------------+ +| Predicate | Description | ++====================+========================================================================================+ +| ``getAge()`` | returns the age of the person (in years) as an ``int`` | ++--------------------+----------------------------------------------------------------------------------------+ +| ``getHairColor()`` | returns the hair color of the person as a ``string`` | ++--------------------+----------------------------------------------------------------------------------------+ +| ``getHeight()`` | returns the height of the person (in cm) as a ``float`` | ++--------------------+----------------------------------------------------------------------------------------+ +| ``getLocation()`` | returns the location of the person's home (north, south, east or west) as a ``string`` | ++--------------------+----------------------------------------------------------------------------------------+ + +We've stored these predicates in the QL library ``tutorial.qll``. To access this library, type ``import tutorial`` in the query console. + +Libraries are convenient for storing commonly used predicates. This saves you from defining a predicate every time you need it. Instead you can just ``import`` the library and use the predicate directly. Once you have imported the library, you can apply any of these predicates to an expression by appending it. + +For example, ``t.getHeight()`` applies ``getHeight()`` to ``t`` and returns the height of ``t``. + +Start the search +----------------- + +The villagers answered "yes" to the question "Is the thief taller than 150cm?" To use this information, you can write the following query to list all villagers taller than 150cm. These are all possible suspects. + +.. code-block:: ql + + from Person t + where t.getHeight() > 150 + select t + +The first line, ``from Person t``, declares that ``t`` must be a ``Person``. We say that the `type `__ of ``t`` is ``Person``. + +Before you use the rest of your answers in your QL search, here are some more tools and examples to help you write your own QL queries: + +Logical connectives +------------------- + +Using `logical connectives `__, you can write more complex queries that combine different pieces of information. + +For example, if you know that the thief is older than 30 *and* has brown hair, you can use the following ``where`` clause to link two predicates: + +.. code-block:: ql + + where t.getAge() > 30 and t.getHairColor() = "brown" + +.. pull-quote:: + + Note + + The predicate ``getHairColor()`` returns a ``string``, so we need to include quotation marks around the result ``"brown"``. + +If the thief does *not* live north of the castle, you can use: + +.. code-block:: ql + + where not t.getLocation() = "north" + +If the thief has brown hair *or* black hair, you can use: + +.. code-block:: ql + + where t.getHairColor() = "brown" or t.getHairColor() = "black" + +You can also combine these connectives into longer statements: + +.. code-block:: ql + + where t.getAge() > 30 + and (t.getHairColor() = "brown" or t.getHairColor() = "black") + and not t.getLocation() = "north" + +.. pull-quote:: + + Note + + We've placed parentheses around the ``or`` clause to make sure that the query is evaluated as intended. Without parentheses, the connective ``and`` takes precedence over ``or``. + +Predicates don't always return exactly one value. For example, if a person ``p`` has black hair which is turning gray, ``p.getHairColor()`` will return two values: black and gray. + +What if the thief is bald? In that case, the thief has no hair, so the ``getHairColor()`` predicate simply doesn't return any results! + +If you know that the thief definitely isn't bald, then there must be a color that matches the thief's hair color. One way to express this in QL is to introduce a new variable ``c`` of type ``string`` and select those ``t`` where ``t.getHairColor()`` matches a value of ``c``. + +.. code-block:: ql + + from Person t, string c + where t.getHairColor() = c + select t + +Notice that we have only temporarily introduced the variable ``c`` and we didn't need it at all in the ``select`` clause. In this case, it is better to use ``exists``: + +.. code-block:: ql + + from Person t + where exists(string c | t.getHairColor() = c) + select t + +``exists`` introduces a temporary variable ``c`` of type ``string`` and holds only if there is at least one ``string c`` that satisfies ``t.getHairColor() = c``. + +.. pull-quote:: + + Note + + If you are familiar with logic, you may notice that ``exists`` in QL corresponds to the existential `quantifier `__ in logic. QL also has a universal quantifier ``forall(vars | formula 1 | formula 2)`` which is logically equivalent to ``not exists(vars | formula 1 | not formula 2)``. + +The real investigation +---------------------- + +You are now ready to track down the thief! Using the examples above, write a query to find the people who satisfy the answers to the first eight questions: + ++---+--------------------------------------------------------+--------+ +| | Question | Answer | ++===+========================================================+========+ +| 1 | Is the thief taller than 150 cm? | yes | ++---+--------------------------------------------------------+--------+ +| 2 | Does the thief have blond hair? | no | ++---+--------------------------------------------------------+--------+ +| 3 | Is the thief bald? | no | ++---+--------------------------------------------------------+--------+ +| 4 | Is the thief younger than 30? | no | ++---+--------------------------------------------------------+--------+ +| 5 | Does the thief live east of the castle? | yes | ++---+--------------------------------------------------------+--------+ +| 6 | Does the thief have black or brown hair? | yes | ++---+--------------------------------------------------------+--------+ +| 7 | Is the thief taller than 180cm and shorter than 190cm? | no | ++---+--------------------------------------------------------+--------+ +| 8 | Is the thief the oldest person in the village? | no | ++---+--------------------------------------------------------+--------+ + +Hints +^^^^^ + +#. Don't forget to ``import tutorial``! +#. Translate each question into QL separately. Look at the examples above if you get stuck. +#. For question 3, remember that a bald person does not have a hair color. +#. For question 8, note that if a person is *not* the oldest, then there is at least one person who is older than them. +#. Combine the conditions using logical connectives to get a query of the form: + +.. code-block:: ql + + import tutorial + + from Person t + where and + not and + ... + select t + +Once you have finished, you will have a list of possible suspects. One of those people must be the thief! + +➤ `See the answer in the query console on LGTM.com `__ + +.. pull-quote:: + + Note + + In the answer, we used ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is just a *comment*. + +You are getting closer to solving the mystery! Unfortunately, you still have quite a long list of suspects... To find out which of your suspects is the thief, you must gather more information and refine your query in the next step. + +More advanced queries +--------------------- + +What if you want to find the oldest, youngest, tallest, or shortest person in the village? As mentioned in the previous topic, you can do this using ``exists``. However, there is also a more efficient way to do this in QL using functions like ``max`` and ``min``. These are examples of `aggregates `__. + +In general, an aggregate is a function that performs an operation on multiple pieces of data and returns a single value as its output. Common aggregates are ``count``, ``max``, ``min``, ``avg`` (average) and ``sum``. The general way to use an aggregate is: + +.. code-block:: ql + + ( | | ) + +For example, you can use the ``max`` aggregate to find the age of the oldest person in the village: + +.. code-block:: ql + + max(int i | exists(Person p | p.getAge() = i) | i) + +This aggregate considers all integers ``i``, limits ``i`` to values that match the ages of people in the village, and then returns the largest matching integer. + +But how can you use this in an actual query? + +If the thief is the oldest person in the village, then you know that the thief's age is equal to the maximum age of the villagers: + +.. code-block:: ql + + from Person t + where t.getAge() = max(int i | exists(Person p | p.getAge() = i) | i) + select t + +This general aggregate syntax is quite long and inconvenient. In most cases, you can omit certain parts of the aggregate. A particularly helpful QL feature is *ordered aggregation*. This allows you to order the expression using ``order by``. + +For example, selecting the oldest villager becomes much simpler if you use an ordered aggregate. + +.. code-block:: ql + + select max(Person p | | p order by p.getAge()) + +The ordered aggregate considers every person ``p`` and selects the person with the maximum age. In this case, there are no restrictions on what people to consider, so the ```` clause is empty. Note that if there are several people with the same maximum age, the query lists all of them. + +Here are some more examples of aggregates: + ++-------------------------------------------------------------------------+---------------------------------------------------+ +| Example | Result | ++=========================================================================+===================================================+ +| ``min(Person p | p.getLocation() = "east" | p order by p.getHeight())`` | shortest person in the east of the village | ++-------------------------------------------------------------------------+---------------------------------------------------+ +| ``count(Person p | p.getLocation() = "south" | p)`` | number of people in the south of the village | ++-------------------------------------------------------------------------+---------------------------------------------------+ +| ``avg(Person p | | p.getHeight())`` | average height of the villagers | ++-------------------------------------------------------------------------+---------------------------------------------------+ +| ``sum(Person p | p.getHairColor() = "brown" | p.getAge())`` | combined age of all the villagers with brown hair | ++-------------------------------------------------------------------------+---------------------------------------------------+ + +Capture the culprit +------------------- + +You can now translate the remaining questions into QL: + ++-----+--------------------------------------------------------------------+--------+ +| | Question | Answer | ++=====+====================================================================+========+ +| ... | ... | ... | ++-----+--------------------------------------------------------------------+--------+ +| 9 | Is the thief the tallest person in the village? | no | ++-----+--------------------------------------------------------------------+--------+ +| 10 | Is the thief shorter than the average villager? | yes | ++-----+--------------------------------------------------------------------+--------+ +| 11 | Is the thief the oldest person in the eastern part of the village? | yes | ++-----+--------------------------------------------------------------------+--------+ + +Have you found the thief? + +➤ `See the answer in the query console on LGTM.com `__ + +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>`. diff --git a/docs/language/learn-ql/beginner/find-thief-1.rst b/docs/language/learn-ql/beginner/find-thief-1.rst deleted file mode 100644 index 3df6c108837..00000000000 --- a/docs/language/learn-ql/beginner/find-thief-1.rst +++ /dev/null @@ -1,71 +0,0 @@ -Find the thief: Introduction -============================ - -There is a small village hidden away in the mountains. The village is divided into four parts—north, south, east, and west—and in the center stands a dark and mysterious castle... Inside the castle, locked away in the highest tower, lies the king's valuable golden crown. One night, a terrible crime is committed. A thief breaks into the tower and steals the crown! - -You know that the thief must live in the village, since nobody else knew about the crown. After some expert detective work, you obtain a list of all the people in the village and some of their personal details. - -+------+-----+------------+--------+----------+ -| Name | Age | Hair color | Height | Location | -+======+=====+============+========+==========+ -| ... | ... | ... | ... | ... | -+------+-----+------------+--------+----------+ - -Sadly, you still have no idea who could have stolen the crown so you walk around the village to find clues. The villagers act very suspiciously and you are convinced they have information about the thief. They refuse to share their knowledge with you directly, but they reluctantly agree to answer questions. They are still not very talkative and **only answer questions with 'yes' or 'no'**. - -You start asking some creative questions and making notes of the answers so you can compare them with your information later: - -+------+--------------------------------------------------------------------+--------+ -| | Question | Answer | -+======+====================================================================+========+ -| (1) | Is the thief taller than 150 cm? | yes | -+------+--------------------------------------------------------------------+--------+ -| (2) | Does the thief have blond hair? | no | -+------+--------------------------------------------------------------------+--------+ -| (3) | Is the thief bald? | no | -+------+--------------------------------------------------------------------+--------+ -| (4) | Is the thief younger than 30? | no | -+------+--------------------------------------------------------------------+--------+ -| (5) | Does the thief live east of the castle? | yes | -+------+--------------------------------------------------------------------+--------+ -| (6) | Does the thief have black or brown hair? | yes | -+------+--------------------------------------------------------------------+--------+ -| (7) | Is the thief taller than 180cm and shorter than 190cm? | no | -+------+--------------------------------------------------------------------+--------+ -| (8) | Is the thief the tallest person in the village? | no | -+------+--------------------------------------------------------------------+--------+ -| (9) | Is the thief shorter than the average villager? | yes | -+------+--------------------------------------------------------------------+--------+ -| (10) | Is the thief the oldest person in the eastern part of the village? | yes | -+------+--------------------------------------------------------------------+--------+ - -There is too much information to search through by hand, so you decide to use your newly acquired QL skills to help you with your investigation... - -#. Open the `query console `__ to get started. -#. Select a language and a demo project. For this tutorial, any language and project will do. -#. Delete the default code ``import select "hello world"``. - -QL libraries ------------- - -We've defined a number of QL `predicates `__ to help you extract data from your table. A QL predicate is a mini-query that expresses a relation between various pieces of data and describes some of their properties. In this case, the predicates give you information about a person, for example their height or age. - -+--------------------+----------------------------------------------------------------------------------------+ -| Predicate | Description | -+====================+========================================================================================+ -| ``getAge()`` | returns the age of the person (in years) as an ``int`` | -+--------------------+----------------------------------------------------------------------------------------+ -| ``getHairColor()`` | returns the hair color of the person as a ``string`` | -+--------------------+----------------------------------------------------------------------------------------+ -| ``getHeight()`` | returns the height of the person (in cm) as a ``float`` | -+--------------------+----------------------------------------------------------------------------------------+ -| ``getLocation()`` | returns the location of the person's home (north, south, east or west) as a ``string`` | -+--------------------+----------------------------------------------------------------------------------------+ - -We've stored these predicates in the QL library ``tutorial.qll``. To access this library, type ``import tutorial`` in the query console. - -Libraries are convenient for storing commonly used predicates. This saves you from defining a predicate every time you need it. Instead you can just ``import`` the library and use the predicate directly. Once you have imported the library, you can apply any of these predicates to an expression by appending it. - -For example, ``t.getHeight()`` applies ``getHeight()`` to ``t`` and returns the height of ``t``. - -Continue to the next page to :doc:`start the investigation `. diff --git a/docs/language/learn-ql/beginner/find-thief-2.rst b/docs/language/learn-ql/beginner/find-thief-2.rst deleted file mode 100644 index b31f978d36a..00000000000 --- a/docs/language/learn-ql/beginner/find-thief-2.rst +++ /dev/null @@ -1,141 +0,0 @@ -Find the thief: Start the search -================================ - -The villagers answered "yes" to the question "Is the thief taller than 150cm?" To use this information, you can write the following query to list all villagers taller than 150cm. These are all possible suspects. - -.. code-block:: ql - - from Person t - where t.getHeight() > 150 - select t - -The first line, ``from Person t``, declares that ``t`` must be a ``Person``. We say that the `type `__ of ``t`` is ``Person``. - -Before you use the rest of your answers in your QL search, here are some more tools and examples to help you write your own QL queries: - -Logical connectives -------------------- - -Using `logical connectives `__, you can write more complex queries that combine different pieces of information. - -For example, if you know that the thief is older than 30 *and* has brown hair, you can use the following ``where`` clause to link two predicates: - -.. code-block:: ql - - where t.getAge() > 30 and t.getHairColor() = "brown" - -.. pull-quote:: - - Note - - The predicate ``getHairColor()`` returns a ``string``, so we need to include quotation marks around the result ``"brown"``. - -If the thief does *not* live north of the castle, you can use: - -.. code-block:: ql - - where not t.getLocation() = "north" - -If the thief has brown hair *or* black hair, you can use: - -.. code-block:: ql - - where t.getHairColor() = "brown" or t.getHairColor() = "black" - -You can also combine these connectives into longer statements: - -.. code-block:: ql - - where t.getAge() > 30 - and (t.getHairColor() = "brown" or t.getHairColor() = "black") - and not t.getLocation() = "north" - -.. pull-quote:: - - Note - - We've placed parentheses around the ``or`` clause to make sure that the query is evaluated as intended. Without parentheses, the connective ``and`` takes precedence over ``or``. - -Predicates don't always return exactly one value. For example, if a person ``p`` has black hair which is turning gray, ``p.getHairColor()`` will return two values: black and gray. - -What if the thief is bald? In that case, the thief has no hair, so the ``getHairColor()`` predicate simply doesn't return any results! - -If you know that the thief definitely isn't bald, then there must be a color that matches the thief's hair color. One way to express this in QL is to introduce a new variable ``c`` of type ``string`` and select those ``t`` where ``t.getHairColor()`` matches a value of ``c``. - -.. code-block:: ql - - from Person t, string c - where t.getHairColor() = c - select t - -Notice that we have only temporarily introduced the variable ``c`` and we didn't need it at all in the ``select`` clause. In this case, it is better to use ``exists``: - -.. code-block:: ql - - from Person t - where exists(string c | t.getHairColor() = c) - select t - -``exists`` introduces a temporary variable ``c`` of type ``string`` and holds only if there is at least one ``string c`` that satisfies ``t.getHairColor() = c``. - -.. pull-quote:: - - Note - - If you are familiar with logic, you may notice that ``exists`` in QL corresponds to the existential `quantifier `__ in logic. QL also has a universal quantifier ``forall(vars | formula 1 | formula 2)`` which is logically equivalent to ``not exists(vars | formula 1 | not formula 2)``. - -The real investigation ----------------------- - -You are now ready to track down the thief! Using the examples above, write a query to find the people who satisfy the answers to the first eight questions: - -+---+--------------------------------------------------------+--------+ -| | Question | Answer | -+===+========================================================+========+ -| 1 | Is the thief taller than 150 cm? | yes | -+---+--------------------------------------------------------+--------+ -| 2 | Does the thief have blond hair? | no | -+---+--------------------------------------------------------+--------+ -| 3 | Is the thief bald? | no | -+---+--------------------------------------------------------+--------+ -| 4 | Is the thief younger than 30? | no | -+---+--------------------------------------------------------+--------+ -| 5 | Does the thief live east of the castle? | yes | -+---+--------------------------------------------------------+--------+ -| 6 | Does the thief have black or brown hair? | yes | -+---+--------------------------------------------------------+--------+ -| 7 | Is the thief taller than 180cm and shorter than 190cm? | no | -+---+--------------------------------------------------------+--------+ -| 8 | Is the thief the oldest person in the village? | no | -+---+--------------------------------------------------------+--------+ - -Hints -^^^^^ - -#. Don't forget to ``import tutorial``! -#. Translate each question into QL separately. Look at the examples above if you get stuck. -#. For question 3, remember that a bald person does not have a hair color. -#. For question 8, note that if a person is *not* the oldest, then there is at least one person who is older than them. -#. Combine the conditions using logical connectives to get a query of the form: - -.. code-block:: ql - - import tutorial - - from Person t - where and - not and - ... - select t - -Once you have finished, you will have a list of possible suspects. One of those people must be the thief! - -➤ `See the answer in the query console `__ - -.. pull-quote:: - - Note - - In the answer, we used ``/*`` and ``*/`` to label the different parts of the query. Any text surrounded by ``/*`` and ``*/`` is not evaluated as part of the QL code, but is just a *comment*. - -You are getting closer to solving the mystery! Unfortunately, you still have quite a long list of suspects... To find out which of your suspects is the thief, you must gather more information and refine your query in the :doc:`next step `. diff --git a/docs/language/learn-ql/beginner/find-thief-3.rst b/docs/language/learn-ql/beginner/find-thief-3.rst deleted file mode 100644 index f8323147cf1..00000000000 --- a/docs/language/learn-ql/beginner/find-thief-3.rst +++ /dev/null @@ -1,80 +0,0 @@ -Find the thief: More advanced queries -===================================== - -What if you want to find the oldest, youngest, tallest, or shortest person in the village? As mentioned in the previous topic, you can do this using ``exists``. However, there is also a more efficient way to do this in QL using functions like ``max`` and ``min``. These are examples of `aggregates `__. - -In general, an aggregate is a function that performs an operation on multiple pieces of data and returns a single value as its output. Common aggregates are ``count``, ``max``, ``min``, ``avg`` (average) and ``sum``. The general way to use an aggregate is: - -.. code-block:: ql - - ( | | ) - -For example, you can use the ``max`` aggregate to find the age of the oldest person in the village: - -.. code-block:: ql - - max(int i | exists(Person p | p.getAge() = i) | i) - -This aggregate considers all integers ``i``, limits ``i`` to values that match the ages of people in the village, and then returns the largest matching integer. - -But how can you use this in an actual query? - -If the thief is the oldest person in the village, then you know that the thief's age is equal to the maximum age of the villagers: - -.. code-block:: ql - - from Person t - where t.getAge() = max(int i | exists(Person p | p.getAge() = i) | i) - select t - -This general aggregate syntax is quite long and inconvenient. In most cases, you can omit certain parts of the aggregate. A particularly helpful QL feature is *ordered aggregation*. This allows you to order the expression using ``order by``. - -For example, selecting the oldest villager becomes much simpler if you use an ordered aggregate. - -.. code-block:: ql - - select max(Person p | | p order by p.getAge()) - -The ordered aggregate considers every person ``p`` and selects the person with the maximum age. In this case, there are no restrictions on what people to consider, so the ```` clause is empty. Note that if there are several people with the same maximum age, the query lists all of them. - -Here are some more examples of aggregates: - -+-------------------------------------------------------------------------+---------------------------------------------------+ -| Example | Result | -+=========================================================================+===================================================+ -| ``min(Person p | p.getLocation() = "east" | p order by p.getHeight())`` | shortest person in the east of the village | -+-------------------------------------------------------------------------+---------------------------------------------------+ -| ``count(Person p | p.getLocation() = "south" | p)`` | number of people in the south of the village | -+-------------------------------------------------------------------------+---------------------------------------------------+ -| ``avg(Person p | | p.getHeight())`` | average height of the villagers | -+-------------------------------------------------------------------------+---------------------------------------------------+ -| ``sum(Person p | p.getHairColor() = "brown" | p.getAge())`` | combined age of all the villagers with brown hair | -+-------------------------------------------------------------------------+---------------------------------------------------+ - -Capture the culprit -------------------- - -You can now translate the remaining questions into QL: - -+-----+--------------------------------------------------------------------+--------+ -| | Question | Answer | -+=====+====================================================================+========+ -| ... | ... | ... | -+-----+--------------------------------------------------------------------+--------+ -| 9 | Is the thief the tallest person in the village? | no | -+-----+--------------------------------------------------------------------+--------+ -| 10 | Is the thief shorter than the average villager? | yes | -+-----+--------------------------------------------------------------------+--------+ -| 11 | Is the thief the oldest person in the eastern part of the village? | yes | -+-----+--------------------------------------------------------------------+--------+ - -Have you found the thief? - -➤ `See the answer in the query console `__ - -What next? ----------- - -- 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 handbook `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. diff --git a/docs/language/learn-ql/beginner/fire-2.rst b/docs/language/learn-ql/beginner/fire-2.rst deleted file mode 100644 index 0f5312e69f0..00000000000 --- a/docs/language/learn-ql/beginner/fire-2.rst +++ /dev/null @@ -1,43 +0,0 @@ -Catch the fire starter: Bald bandits -==================================== - -You ask the northerners if they have any more information about the fire starters. Luckily, you have a witness! The farmer living next to the field saw two people run away just after the fire started. He only saw the tops of their heads, and noticed that they were both bald. - -This is a very helpful clue. Remember that you wrote a QL query to select all bald people: - -.. code-block:: ql - - from Person p - where not exists (string c | p.getHairColor() = c) - select p - -To avoid having to type ``not exists (string c | p.getHairColor() = c)`` every time you want to select a bald person, you can instead define another new predicate ``isBald``. - -.. code-block:: ql - - predicate isBald(Person p) { - not exists (string c | p.getHairColor() = c) - } - -The property ``isBald(p)`` holds whenever ``p`` is bald, so you can replace the previous query with: - -.. code-block:: ql - - from Person p - where isBald(p) - select p - -The predicate ``isBald`` is defined to take a ``Person``, so it can also take a ``Southerner``, as ``Southerner`` is a subtype of ``Person``. It can't take an ``int`` for example—that would cause an error. - -You can now write a query to select the bald southerners who are allowed into the north. - -➤ `See the answer in the query console `__ - -You have found the two fire starters! They are arrested and the villagers are once again impressed with your work. - -What next? ----------- - -- 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 handbook `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. diff --git a/docs/language/learn-ql/beginner/ql-tutorials.rst b/docs/language/learn-ql/beginner/ql-tutorials.rst index 2f3d6cc5e5d..a8dd35ff617 100644 --- a/docs/language/learn-ql/beginner/ql-tutorials.rst +++ b/docs/language/learn-ql/beginner/ql-tutorials.rst @@ -1,27 +1,19 @@ -QL detective tutorials -====================== +QL tutorials +============ + +Solve puzzles to learn the basics of QL before you analyze code with CodeQL. The tutorials teach you how to write queries and introduce you to key logic concepts along the way. .. toctree:: - :glob: :hidden: - ./* + ../introduction-to-ql + find-the-thief + catch-the-fire-starter + crown-the-rightful-heir + cross-the-river -Welcome to the detective tutorials! These are aimed at complete beginners who would like to learn the basics of QL, -before analyzing code with CodeQL. -The tutorials teach you how to write queries and introduce you to key logic concepts along the way. - -We recommend you first read the :doc:`Introduction to QL <../introduction-to-ql>` page for a description of the language and -some simple examples. - -Currently the following detective tutorials are available: - -- :doc:`Find the thief `—a three part mystery that introduces logical connectives, quantifiers, and aggregates -- :doc:`Catch the fire starter `—an intriguing search that introduces predicates and classes -- :doc:`Crown the rightful heir `—a detective puzzle that introduces recursion - -Further resources ------------------ - -- For a summary of available learning resources, see :doc:`Learning CodeQL <../../index>`. -- For an overview of the important concepts in QL, see the `QL language handbook `__. +- :doc:`Introduction to QL <../introduction-to-ql>`: Work through some simple exercises and examples to learn about the basics of QL and CodeQL. +- :doc:`Find the thief `: Take on the role of a detective to find the thief in this fictional village. You will learn how to use logical connectives, quantifiers, and aggregates in QL along the way. +- :doc:`Catch the fire starter `: Learn about QL predicates and classes to solve your second mystery as a QL detective. +- :doc:`Crown the rightful heir `: This is a QL detective puzzle that shows you how to use recursion in QL to write more complex queries. +- :doc:`Cross the river `: Use common QL features to write a query that finds a solution to the "River crossing" logic puzzle. diff --git a/docs/language/learn-ql/ql-etudes/river-crossing-1.ql b/docs/language/learn-ql/beginner/river-crossing-1.ql similarity index 100% rename from docs/language/learn-ql/ql-etudes/river-crossing-1.ql rename to docs/language/learn-ql/beginner/river-crossing-1.ql diff --git a/docs/language/learn-ql/ql-etudes/river-crossing.ql b/docs/language/learn-ql/beginner/river-crossing.ql similarity index 100% rename from docs/language/learn-ql/ql-etudes/river-crossing.ql rename to docs/language/learn-ql/beginner/river-crossing.ql diff --git a/docs/language/learn-ql/cpp/conversions-classes.rst b/docs/language/learn-ql/cpp/conversions-classes.rst index 016efa50d67..553423bb47e 100644 --- a/docs/language/learn-ql/cpp/conversions-classes.rst +++ b/docs/language/learn-ql/cpp/conversions-classes.rst @@ -1,15 +1,14 @@ -Tutorial: Conversions and classes -================================= +Conversions and classes in C and C++ +==================================== -Overview --------- - -This topic contains worked examples of how to write queries using the CodeQL library classes for C/C++ conversions and classes. +You can use the standard CodeQL libraries for C and C++ to detect when the type of an expression is changed. Conversions ----------- -Let us take a look at the ``Conversion`` class in the standard library: +In C and C++, conversions change the type of an expression. They may be implicit conversions generated by the compiler, or explicit conversions requested by the user. + +Let's take a look at the `Conversion `__ class in the standard library: - ``Expr`` @@ -25,8 +24,6 @@ Let us take a look at the ``Conversion`` class in the standard library: - ``ArrayToPointerConversion`` - ``VirtualMemberToFunctionPointerConversion`` -All conversions change the type of an expression. They may be implicit conversions (generated by the compiler) or explicit conversions (requested by the user). - Exploring the subexpressions of an assignment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -166,7 +163,7 @@ Our starting point for the query is pairs of a base class and a derived class, c where derived.getABaseClass+() = base select base, derived, "The second class is derived from the first." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Note that the transitive closure symbol ``+`` indicates that ``Class.getABaseClass()`` may be followed one or more times, rather than only accepting a direct base class. @@ -178,7 +175,7 @@ A lot of the results are uninteresting template parameters. You can remove those and not exists(base.getATemplateArgument()) and not exists(derived.getATemplateArgument()) -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Finding derived classes with destructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -197,7 +194,7 @@ Now we can extend the query to find derived classes with destructors, using the and d2 = derived.getDestructor() select base, derived, "The second class is derived from the first, and both have a destructor." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Notice that getting the destructor implicitly asserts that one exists. As a result, this version of the query returns fewer results than before. @@ -217,17 +214,17 @@ Our last change is to use ``Function.isVirtual()`` to find cases where the base and not d1.isVirtual() select d1, "This destructor should probably be virtual." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ That completes the query. -There is a similar built-in LGTM `query `__ that finds classes in a C/C++ project with virtual functions but no virtual destructor. You can take a look at the code for this query by clicking **Open in query console** at the top of that page. +There is a similar built-in `query `__ on LGTM.com that finds classes in a C/C++ project with virtual functions but no virtual destructor. You can take a look at the code for this query by clicking **Open in query console** at the top of that page. -What next? ----------- +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/C++ ` tutorial. -- Try the worked examples in the following topics: :doc:`Example: Checking that constructors initialize all private fields `, and :doc:`Example: Checking for allocations equal to 'strlen(string)' without space for a null terminator `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/cpp/dataflow.rst b/docs/language/learn-ql/cpp/dataflow.rst index 686759c049f..dcdc7aab1d4 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -1,13 +1,12 @@ -Analyzing data flow in C/C++ -============================ +Analyzing data flow in C and C++ +================================ -Overview --------- +You can use data flow analysis to track the flow of potentially malicious or insecure data that can cause vulnerabilities in your codebase. -This topic describes how data flow analysis is implemented in the CodeQL libraries for C/C++ and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. +About data flow +--------------- -For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. +Data flow analysis computes the possible values that a variable can hold at various points in a program, determining how those values propagate through the program, and where they are used. In CodeQL, you can model both local data flow and global data flow. For a more general introduction to modeling data flow, see :doc:`About data flow analysis <../intro-to-data-flow>`. Local data flow --------------- @@ -140,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 ~~~~~~~~~~~~~~~~~~~~~~ @@ -296,12 +299,12 @@ 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>`__) -What next? ----------- +Further reading +--------------- -- Try the worked examples in the following topics: :doc:`Example: Checking that constructors initialize all private fields ` and :doc:`Example: Checking for allocations equal to 'strlen(string)' without space for a null terminator `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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 ------- diff --git a/docs/language/learn-ql/cpp/expressions-types.rst b/docs/language/learn-ql/cpp/expressions-types.rst index 1595d594683..39da25330d3 100644 --- a/docs/language/learn-ql/cpp/expressions-types.rst +++ b/docs/language/learn-ql/cpp/expressions-types.rst @@ -1,13 +1,10 @@ -Tutorial: Expressions, types and statements -=========================================== +Expressions, types, and statements in C and C++ +=============================================== -Overview --------- +You can use CodeQL to explore expressions, types, and statements in C and C++ code to find, for example, incorrect assignments. -This topic contains worked examples of how to write queries using the standard CodeQL library classes for C/C++ expressions, types, and statements. - -Expressions and types ---------------------- +Expressions and types in CodeQL +------------------------------- Each part of an expression in C becomes an instance of the ``Expr`` class. For example, the C code ``x = x + 1`` becomes an ``AssignExpr``, an ``AddExpr``, two instances of ``VariableAccess`` and a ``Literal``. All of these CodeQL classes extend ``Expr``. @@ -24,7 +21,7 @@ In the following example we find instances of ``AssignExpr`` which assign the co where e.getRValue().getValue().toInt() = 0 select e, "Assigning the value 0 to something." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ The ``where`` clause in this example gets the expression on the right side of the assignment, ``getRValue()``, and compares it with zero. Notice that there are no checks to make sure that the right side of the assignment is an integer or that it has a value (that is, it is compile-time constant, rather than a variable). For expressions where either of these assumptions is wrong, the associated predicate simply does not return anything and the ``where`` clause will not produce a result. You could think of it as if there is an implicit ``exists(e.getRValue().getValue().toInt())`` at the beginning of this line. @@ -34,7 +31,7 @@ It is also worth noting that the query above would find this C code: yPtr = NULL; -This is because the database contains a representation of the code base after the preprocessor transforms have run (for more information, see `Database generation `__). This means that any macro invocations, such as the ``NULL`` define used here, are expanded during the creation of the database. If you want to write queries about macros then there are some special library classes that have been designed specifically for this purpose (for example, the ``Macro``, ``MacroInvocation`` classes and predicates like ``Element.isInMacroExpansion()``). In this case, it is good that macros are expanded, but we do not want to find assignments to pointers. +This is because the database contains a representation of the code base after the preprocessor transforms have run. This means that any macro invocations, such as the ``NULL`` define used here, are expanded during the creation of the database. If you want to write queries about macros then there are some special library classes that have been designed specifically for this purpose (for example, the ``Macro``, ``MacroInvocation`` classes and predicates like ``Element.isInMacroExpansion()``). In this case, it is good that macros are expanded, but we do not want to find assignments to pointers. For more information, see `Database generation `__ on LGTM.com. Finding assignments of 0 to an integer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -50,7 +47,7 @@ We can make the query more specific by defining a condition for the left side of and e.getLValue().getType().getUnspecifiedType() instanceof IntegralType select e, "Assigning the value 0 to an integer." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ This checks that the left side of the assignment has a type that is some kind of integer. Note the call to ``Type.getUnspecifiedType()``. This resolves ``typedef`` types to their underlying types so that the query finds assignments like this one: @@ -61,8 +58,8 @@ This checks that the left side of the assignment has a type that is some kind of i = 0; -Statements ----------- +Statements in CodeQL +-------------------- We can refine the query further using statements. In this case we use the class ``ForStmt``: @@ -110,7 +107,7 @@ Unfortunately this would not quite work, because the loop initialization is actu and e.getLValue().getType().getUnspecifiedType() instanceof IntegralType select e, "Assigning the value 0 to an integer, inside a for loop initialization." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Finding assignments of 0 within the loop body ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -128,14 +125,14 @@ We can find assignments inside the loop body using similar code with the predica and e.getLValue().getType().getUnderlyingType() instanceof IntegralType select e, "Assigning the value 0 to an integer, inside a for loop body." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Note that we replaced ``e.getEnclosingStmt()`` with ``e.getEnclosingStmt().getParentStmt*()``, to find an assignment expression that is deeply nested inside the loop body. The transitive closure modifier ``*`` here indicates that ``Stmt.getParentStmt()`` may be followed zero or more times, rather than just once, giving us the statement, its parent statement, its parent's parent statement etc. -What next? ----------- +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 ` and :doc:`Analyzing data flow in C/C++ ` tutorials. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/cpp/function-classes.rst b/docs/language/learn-ql/cpp/function-classes.rst index 51f07a8d0f0..841add0d4b0 100644 --- a/docs/language/learn-ql/cpp/function-classes.rst +++ b/docs/language/learn-ql/cpp/function-classes.rst @@ -1,10 +1,12 @@ -Tutorial: Function classes -========================== +Functions in C and C++ +======================= + +You can use CodeQL to explore functions in C and C++ code. Overview -------- -The standard CodeQL library for C and C++ represents functions using the ``Function`` class (see :doc:`Introducing the C/C++ libraries `). +The standard CodeQL library for C and C++ represents functions using the ``Function`` class (see :doc:`CodeQL libraries for C and C++ `). The example queries in this topic explore some of the most useful library predicates for querying functions. @@ -26,7 +28,7 @@ This query is very general, so there are probably too many results to be interes Finding functions that are not called ------------------------------------- -It might be more interesting to find functions that are not called, using the standard CodeQL ``FunctionCall`` class from the **abstract syntax tree** category (see :doc:`Introducing the C/C++ libraries `). The ``FunctionCall`` class can be used to identify places where a function is actually used, and it is related to ``Function`` through the ``FunctionCall.getTarget()`` predicate. +It might be more interesting to find functions that are not called, using the standard CodeQL ``FunctionCall`` class from the **abstract syntax tree** category (see :doc:`CodeQL libraries for C and C++ `). The ``FunctionCall`` class can be used to identify places where a function is actually used, and it is related to ``Function`` through the ``FunctionCall.getTarget()`` predicate. .. code-block:: ql @@ -36,7 +38,7 @@ It might be more interesting to find functions that are not called, using the st where not exists(FunctionCall fc | fc.getTarget() = f) select f, "This function is never called." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ The new query finds functions that are not the target of any ``FunctionCall``—in other words, functions that are never called. You may be surprised by how many results the query finds. However, if you examine the results, you can see that many of the functions it finds are used indirectly. To create a query that finds only unused functions, we need to refine the query and exclude other ways of using a function. @@ -54,7 +56,7 @@ You can modify the query to remove functions where a function pointer is used to and not exists(FunctionAccess fa | fa.getTarget() = f) select f, "This function is never called, or referenced with a function pointer." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ This query returns fewer results. However, if you examine the results then you can probably still find potential refinements. @@ -76,7 +78,7 @@ This query uses ``Function`` and ``FunctionCall`` to find calls to the function and not fc.getArgument(1) instanceof StringLiteral select fc, "sprintf called with variable format string." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ This uses: @@ -87,10 +89,10 @@ Note that we could have used ``Declaration.getName()``, but ``Declaration.getQua The LGTM version of this query is considerably more complicated, but if you look carefully you will find that its structure is the same. See `Non-constant format string `__ and click **Open in query console** at the top of the page. -What next? ----------- +Further reading +--------------- - Explore other ways of finding functions using examples from the `C/C++ cookbook `__. -- Take a look at some of the other tutorials: :doc:`Expressions, types and statements `, :doc:`Conversions and classes `, and :doc:`Analyzing data flow in C/C++ `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/cpp/guards.rst b/docs/language/learn-ql/cpp/guards.rst index f21a7f866e5..409df0a8f81 100644 --- a/docs/language/learn-ql/cpp/guards.rst +++ b/docs/language/learn-ql/cpp/guards.rst @@ -1,8 +1,10 @@ Using the guards library in C and C++ ===================================== -Overview --------- +You can use the CodeQL guards library to identify conditional expressions that control the execution of other parts of a program in C and C++ codebases. + +About the guards library +------------------------ The guards library (defined in ``semmle.code.cpp.controlflow.Guards``) provides a class `GuardCondition `__ representing Boolean values that are used to make control flow decisions. A ``GuardCondition`` is considered to guard a basic block if the block can only be reached if the ``GuardCondition`` is evaluated a certain way. For instance, in the following code, ``x < 10`` is a ``GuardCondition``, and it guards all the code before the return statement. @@ -20,7 +22,7 @@ A ``GuardCondition`` is considered to guard a basic block if the block can only The ``controls`` predicate ------------------------------------------------- +-------------------------- The ``controls`` predicate helps determine which blocks are only run when the ``GuardCondition`` evaluates a certain way. ``guard.controls(block, testIsTrue)`` holds if ``block`` is only entered if the value of this condition is ``testIsTrue``. diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index 9e7e910e78e..4960cfc5dba 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -1,10 +1,13 @@ -Introducing the CodeQL libraries for C/C++ -========================================== +CodeQL library for C and C++ +============================ -Overview --------- +When analyzing C or C++ code, you can use the large collection of classes in the CodeQL library for C and C++. -There is an extensive library for analyzing CodeQL databases extracted from C/C++ projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``cpp.qll`` imports all the core C/C++ library modules, so you can include the complete library by beginning your query with: +About the CodeQL library for C and C++ +-------------------------------------- + +There is an extensive library for analyzing CodeQL databases extracted from C/C++ projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. +The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``cpp.qll`` imports all the core C/C++ library modules, so you can include the complete library by beginning your query with: .. code-block:: ql @@ -12,9 +15,7 @@ There is an extensive library for analyzing CodeQL databases extracted from C/C+ The rest of this topic summarizes the available CodeQL classes and corresponding C/C++ constructs. -NOTE: You can find related classes and features using the query console's auto-complete feature. You can also press *F3* to jump to the definition of any element; library files are opened in new tabs in the console. - -Summary of the library classes +Commonly-used library classes ------------------------------ The most commonly used standard library classes are listed below. The listing is broken down by functionality. Each library class is annotated with a C/C++ construct it corresponds to. @@ -521,9 +522,9 @@ This table lists `Preprocessor `, :doc:`Expressions, types and statements `, :doc:`Conversions and classes `, and :doc:`Analyzing data flow in C/C++ `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- Experiment with the worked examples in the CodeQL for C/C++ topics: :doc:`Functions in C and C++ `, :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. diff --git a/docs/language/learn-ql/cpp/private-field-initialization.rst b/docs/language/learn-ql/cpp/private-field-initialization.rst index 26b57660142..c1f9224a145 100644 --- a/docs/language/learn-ql/cpp/private-field-initialization.rst +++ b/docs/language/learn-ql/cpp/private-field-initialization.rst @@ -1,13 +1,15 @@ -Example: Checking that constructors initialize all private fields -================================================================= +Refining a query to account for edge cases +========================================== + +You can improve the results generated by a CodeQL query by adding conditions to remove false positive results caused by common edge cases. Overview -------- -This topic describes how a C++ query was developed. The example introduces recursive predicates and demonstrates the typical workflow used to refine a query. For a full overview of the topics available for learning to write queries for C/C++ code, see :doc:`CodeQL for C/C++ `. +This topic describes how a C++ query was developed. The example introduces recursive predicates and demonstrates the typical workflow used to refine a query. For a full overview of the topics available for learning to write queries for C/C++ code, see :doc:`CodeQL for C and C++ `. -Problem—finding every private field and checking for initialization -------------------------------------------------------------------- +Finding every private field and checking for initialization +----------------------------------------------------------- Writing a query to check if a constructor initializes all private fields seems like a simple problem, but there are several edge cases to account for. @@ -100,7 +102,7 @@ You may also wish to consider methods called by constructors that assign to the int m_value; }; -This case can be excluded by creating a recursive predicate. The recursive predicate is given a function and a field, then checks whether the function assigns to the field. The predicate runs itself on all the functions called by the function that it has been given. By passing the constructor to this predicate, we can check for assignments of a field in all functions called by the constructor, and then do the same for all functions called by those functions all the way down the tree of function calls (see `Recursion `__ for more information). +This case can be excluded by creating a recursive predicate. The recursive predicate is given a function and a field, then checks whether the function assigns to the field. The predicate runs itself on all the functions called by the function that it has been given. By passing the constructor to this predicate, we can check for assignments of a field in all functions called by the constructor, and then do the same for all functions called by those functions all the way down the tree of function calls. For more information, see `Recursion `__ in the QL language reference. .. code-block:: ql @@ -124,7 +126,7 @@ This case can be excluded by creating a recursive predicate. The recursive predi Refinement 4—simplifying the query ---------------------------------- -Finally we can simplify the query by using the `transitive closure operator `__. In this final version of the query, ``c.calls*(fun)`` resolves to the set of all functions that are ``c`` itself, are called by ``c``, are called by a function that is called by ``c``, and so on. This eliminates the need to make a new predicate all together. +Finally we can simplify the query by using the transitive closure operator. In this final version of the query, ``c.calls*(fun)`` resolves to the set of all functions that are ``c`` itself, are called by ``c``, are called by a function that is called by ``c``, and so on. This eliminates the need to make a new predicate all together. For more information, see `Transitive closures `__ in the QL language reference. .. code-block:: ql @@ -142,11 +144,11 @@ Finally we can simplify the query by using the `transitive closure operator `__ +➤ `See this in the query console on LGTM.com `__ -What next? ----------- +Further reading +--------------- -- Take a look at another example: :doc:`Checking for allocations equal to 'strlen(string)' without space for a null terminator `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/cpp/ql-for-cpp.rst b/docs/language/learn-ql/cpp/ql-for-cpp.rst index b1596c7de92..bd52291a7f8 100644 --- a/docs/language/learn-ql/cpp/ql-for-cpp.rst +++ b/docs/language/learn-ql/cpp/ql-for-cpp.rst @@ -1,8 +1,9 @@ -CodeQL for C/C++ -================ +CodeQL for C and C++ +==================== + +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from C and C++ codebases. .. toctree:: - :glob: :hidden: introduce-libraries-cpp @@ -12,47 +13,36 @@ CodeQL for C/C++ dataflow private-field-initialization zero-space-terminator - -These topics provide an overview of the CodeQL libraries for C/C++ and show examples of how to write queries that use them. - -- `Basic C/C++ query `__ describes how to write and run queries using LGTM. - -- :doc:`Introducing the CodeQL libraries for C/C++ ` introduces the standard libraries used to write queries for C and C++ code. - -- :doc:`Tutorial: Function classes ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ functions. - -- :doc:`Tutorial: Expressions, types and statements ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ expressions, types and statements. - -- :doc:`Tutorial: Conversions and classes ` demonstrates how to write queries using the standard CodeQL library classes for C/C++ conversions and classes. - -- :doc:`Tutorial: Analyzing data flow in C/C++ ` demonstrates how to write queries using the standard data flow and taint tracking libraries for C/C++. - -- :doc:`Example: Checking that constructors initialize all private fields ` works through the development of a query. It introduces recursive predicates and shows the typical workflow used to refine a query. - -- :doc:`Example: Checking for allocations equal to strlen(string) without space for a null terminator ` shows how a query to detect this particular buffer issue was developed. - -Advanced libraries ----------------------------------- - -.. toctree:: - :hidden: - guards range-analysis value-numbering-hash-cons -- :doc:`Using the guards library in C and C++ ` demonstrates how to identify conditional expressions that control the execution of other code and what guarantees they provide. -- :doc:`Using range analysis for C and C++ ` demonstrates how to determine constant upper and lower bounds and possible overflow or underflow of expressions. +- `Basic C/C++ query `__: Learn to write and run a simple CodeQL query using LGTM. -- :doc:`Using hash consing and value numbering for C and C++ ` demonstrates how to recognize expressions that are syntactically identical or compute the same value at runtime. +- :doc:`CodeQL library for C and C++ `: When analyzing C or C++ code, you can use the large collection of classes in the CodeQL library for C and C++. +- :doc:`Functions in C and C++ `: You can use CodeQL to explore functions in C and C++ code. -Other resources +- :doc:`Expressions, types, and statements in C and C++ `: You can use CodeQL to explore expressions, types, and statements in C and C++ code to find, for example, incorrect assignments. + +- :doc:`Conversions and classes in C and C++ `: You can use the standard CodeQL libraries for C and C++ to detect when the type of an expression is changed. + +- :doc:`Analyzing data flow in C and C++ `: You can use data flow analysis to track the flow of potentially malicious or insecure data that can cause vulnerabilities in your codebase. + +- :doc:`Refining a query to account for edge cases `: You can improve the results generated by a CodeQL query by adding conditions to remove false positive results caused by common edge cases. + +- :doc:`Detecting a potential buffer overflow `: You can use CodeQL to detect potential buffer overflows by checking for allocations equal to ``strlen`` in C and C++. + +- :doc:`Using the guards library in C and C++ `: You can use the CodeQL guards library to identify conditional expressions that control the execution of other parts of a program in C and C++ codebases. + +- :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 --------------- -.. TODO: Rename the cookbooks: C/C++ cookbook, or C/C++ CodeQL cookbook, or CodeQL cookbook for C/C++, or...? - - 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 c60465e131d..ba324e86ac9 100644 --- a/docs/language/learn-ql/cpp/range-analysis.rst +++ b/docs/language/learn-ql/cpp/range-analysis.rst @@ -1,10 +1,10 @@ Using range analysis for C and C++ ================================== -Overview --------- +You can use range analysis to determine the upper or lower bounds on an expression, or whether an expression could potentially over or underflow. -Range analysis determines upper and lower bounds for an expression. +About the range analysis library +-------------------------------- The range analysis library (defined in ``semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis``) provides a set of predicates for determining constant upper and lower bounds on expressions, as well as recognizing integer overflows. For performance, the library performs automatic widening and therefore may not provide the tightest possible bounds. 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 e05f93dbae1..de102a15f6d 100644 --- a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst +++ b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst @@ -1,15 +1,14 @@ Hash consing and value numbering -================================================= +================================ -Overview --------- +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. + +About the hash consing and value numbering libraries +---------------------------------------------------- In C and C++ databases, each node in the abstract syntax tree is represented by a separate object. This allows both analysis and results display to refer to specific appearances of a piece of syntax. However, it is frequently useful to determine whether two expressions are equivalent, either syntactically or semantically. -The `hash consing `__ library (defined in ``semmle.code.cpp.valuenumbering.HashCons``) provides a mechanism for identifying expressions that have the same syntactic structure. The `global value numbering `__ library (defined in ``semmle.code.cpp.valuenumbering.GlobalValueNumbering``) provides a mechanism for identifying expressions that compute the same value at runtime. - -Both libraries partition the expressions in each function into equivalence classes represented by objects. Each ``HashCons`` object represents a set of expressions with identical parse trees, while ``GVN`` objects represent sets of expressions that will always compute the same value. - +The hash consing library (defined in ``semmle.code.cpp.valuenumbering.HashCons``) provides a mechanism for identifying expressions that have the same syntactic structure. The global value numbering library (defined in ``semmle.code.cpp.valuenumbering.GlobalValueNumbering``) provides a mechanism for identifying expressions that compute the same value at runtime. Both libraries partition the expressions in each function into equivalence classes represented by objects. Each ``HashCons`` object represents a set of expressions with identical parse trees, while ``GVN`` objects represent sets of expressions that will always compute the same value. For more information, see `Hash consing `__ and `Value numbering `__ on Wikipedia. Example C code -------------- @@ -111,4 +110,3 @@ 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" - diff --git a/docs/language/learn-ql/cpp/zero-space-terminator.rst b/docs/language/learn-ql/cpp/zero-space-terminator.rst index a9370f7828d..a25437865f7 100644 --- a/docs/language/learn-ql/cpp/zero-space-terminator.rst +++ b/docs/language/learn-ql/cpp/zero-space-terminator.rst @@ -1,10 +1,7 @@ -Example: Checking for allocations equal to ``strlen(string)`` without space for a null terminator -================================================================================================= +Detecting a potential buffer overflow +===================================== -Overview --------- - -This topic describes how a C/C++ query for detecting a potential buffer overflow was developed. For a full overview of the topics available for learning to write queries for C/C++ code, see :doc:`CodeQL for C/C++ `. +You can use CodeQL to detect potential buffer overflows by checking for allocations equal to ``strlen`` in C and C++. This topic describes how a C/C++ query for detecting a potential buffer overflow was developed. Problem—detecting memory allocation that omits space for a null termination character ------------------------------------------------------------------------------------- @@ -98,7 +95,7 @@ When you have defined the basic query then you can refine the query to include f Improving the query using the 'SSA' library ------------------------------------------- -The ``SSA`` library represents variables in `static single assignment `__ (SSA) form. In this form, each variable is assigned exactly once and every variable is defined before it is used. The use of SSA variables simplifies queries considerably as much of the local data flow analysis has been done for us. +The ``SSA`` library represents variables in static single assignment (SSA) form. In this form, each variable is assigned exactly once and every variable is defined before it is used. The use of SSA variables simplifies queries considerably as much of the local data flow analysis has been done for us. For more information, see `Static single assignment `__ on Wikipedia. Including examples where the string size is stored before use ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -224,8 +221,8 @@ The completed query will now identify cases where the result of ``strlen`` is st where malloc.getAllocatedSize() instanceof StrlenCall select malloc, "This allocation does not include space to null-terminate the string." -What next? ----------- +Further reading +--------------- -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- Find out more about QL in the `QL language reference `__. +- Learn more about the query console in `Using the query console `__ on LGTM.com. diff --git a/docs/language/learn-ql/csharp/dataflow.rst b/docs/language/learn-ql/csharp/dataflow.rst index 3b9bb69d7da..317594b33f2 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -1,13 +1,14 @@ Analyzing data flow in C# ========================= -Overview --------- +You can use CodeQL to track the flow of data through a C# program to its use. -This topic describes how data flow analysis is implemented in the CodeQL libraries for C# and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. +About this article +------------------ -For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. +This article describes how data flow analysis is implemented in the CodeQL libraries for C# and includes examples to help you write your own data flow queries. +The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking. +For a more general introduction to modeling data flow, see :doc:`About data flow analysis <../intro-to-data-flow>`. Local data flow --------------- @@ -17,7 +18,7 @@ Local data flow is data flow within a single method or callable. Local data flow Using local data flow ~~~~~~~~~~~~~~~~~~~~~ -The local data flow library is in the module ``DataFlow``, which defines the class ``Node`` denoting any element that data can flow through. ``Node``\ s are divided into expression nodes (``ExprNode``) and parameter nodes (``ParameterNode``). It is possible to map between data flow nodes and expressions/parameters using the member predicates ``asExpr`` and ``asParameter``: +The local data flow library is in the module ``DataFlow``, which defines the class ``Node`` denoting any element that data can flow through. ``Node``\ s are divided into expression nodes (``ExprNode``) and parameter nodes (``ParameterNode``). You can map between data flow nodes and expressions/parameters using the member predicates ``asExpr`` and ``asParameter``: .. code-block:: ql @@ -45,9 +46,9 @@ or using the predicates ``exprNode`` and ``parameterNode``: */ ParameterNode parameterNode(Parameter p) { ... } -The predicate ``localFlowStep(Node nodeFrom, Node nodeTo)`` holds if there is an immediate data flow edge from the node ``nodeFrom`` to the node ``nodeTo``. The predicate can be applied recursively (using the ``+`` and ``*`` operators), or it is possible to use the predefined recursive predicate ``localFlow``. +The predicate ``localFlowStep(Node nodeFrom, Node nodeTo)`` holds if there is an immediate data flow edge from the node ``nodeFrom`` to the node ``nodeTo``. You can apply the predicate recursively, by using the ``+`` and ``*`` operators, or you can use the predefined recursive predicate ``localFlow``. -For example, finding flow from a parameter ``source`` to an expression ``sink`` in zero or more local steps can be achieved as follows: +For example, you can find flow from a parameter ``source`` to an expression ``sink`` in zero or more local steps: .. code-block:: ql @@ -65,9 +66,9 @@ Local taint tracking extends local data flow by including non-value-preserving f If ``x`` is a tainted string then ``y`` is also tainted. -The local taint tracking library is in the module ``TaintTracking``. Like local data flow, a predicate ``localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)`` holds if there is an immediate taint propagation edge from the node ``nodeFrom`` to the node ``nodeTo``. The predicate can be applied recursively (using the ``+`` and ``*`` operators), or it is possible to use the predefined recursive predicate ``localTaint``. +The local taint tracking library is in the module ``TaintTracking``. Like local data flow, a predicate ``localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)`` holds if there is an immediate taint propagation edge from the node ``nodeFrom`` to the node ``nodeTo``. You can apply the predicate recursively, by using the ``+`` and ``*`` operators, or you can use the predefined recursive predicate ``localTaint``. -For example, finding taint propagation from a parameter ``source`` to an expression ``sink`` in zero or more local steps can be achieved as follows: +For example, you can find taint propagation from a parameter ``source`` to an expression ``sink`` in zero or more local steps: .. code-block:: ql @@ -76,7 +77,7 @@ For example, finding taint propagation from a parameter ``source`` to an express Examples ~~~~~~~~ -The following query finds the filename passed to ``System.IO.File.Open``: +This query finds the filename passed to ``System.IO.File.Open``: .. code-block:: ql @@ -99,7 +100,7 @@ Unfortunately this will only give the expression in the argument, not the values and DataFlow::localFlow(DataFlow::exprNode(src), DataFlow::exprNode(call.getArgument(0))) select src -Then we can make the source more specific, for example an access to a public parameter. The following query finds where a public parameter is used to open a file: +Then we can make the source more specific, for example an access to a public parameter. This query finds instances where a public parameter is used to open a file: .. code-block:: ql @@ -112,7 +113,7 @@ Then we can make the source more specific, for example an access to a public par and call.getEnclosingCallable().(Member).isPublic() select p, "Opening a file from a public method." -The following example finds calls to ``String.Format`` where the format string isn't hard-coded: +This query finds calls to ``String.Format`` where the format string isn't hard-coded: .. code-block:: ql @@ -136,10 +137,14 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~ -The global data flow library is used by extending the class ``DataFlow::Configuration`` as follows: +The global data flow library is used by extending the class ``DataFlow::Configuration``: .. code-block:: ql @@ -157,12 +162,12 @@ The global data flow library is used by extending the class ``DataFlow::Configur } } -The following predicates are defined in the configuration: +These predicates are defined in the configuration: -- ``isSource`` - defines where data may flow from -- ``isSink`` - defines where data may flow to -- ``isBarrier`` - optionally, restricts the data flow -- ``isAdditionalFlowStep`` - optionally, adds additional flow steps +- ``isSource`` - defines where data may flow from. +- ``isSink`` - defines where data may flow to. +- ``isBarrier`` - optionally, restricts the data flow. +- ``isAdditionalFlowStep`` - optionally, adds additional flow steps. The characteristic predicate (``MyDataFlowConfiguration()``) defines the name of the configuration, so ``"..."`` must be replaced with a unique name. @@ -177,7 +182,7 @@ The data flow analysis is performed using the predicate ``hasFlow(DataFlow::Node Using global taint tracking ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Global taint tracking is to global data flow what local taint tracking is to local data flow. That is, global taint tracking extends global data flow with additional non-value-preserving steps. The global taint tracking library is used by extending the class ``TaintTracking::Configuration`` as follows: +Global taint tracking is to global data flow what local taint tracking is to local data flow. That is, global taint tracking extends global data flow with additional non-value-preserving steps. The global taint tracking library is used by extending the class ``TaintTracking::Configuration``: .. code-block:: ql @@ -195,12 +200,12 @@ Global taint tracking is to global data flow what local taint tracking is to loc } } -The following predicates are defined in the configuration: +These predicates are defined in the configuration: -- ``isSource`` - defines where taint may flow from -- ``isSink`` - defines where taint may flow to -- ``isSanitizer`` - optionally, restricts the taint flow -- ``isAdditionalTaintStep`` - optionally, adds additional taint steps +- ``isSource`` - defines where taint may flow from. +- ``isSink`` - defines where taint may flow to. +- ``isSanitizer`` - optionally, restricts the taint flow. +- ``isAdditionalTaintStep`` - optionally, adds additional taint steps. Similar to global data flow, the characteristic predicate (``MyTaintTrackingConfiguration()``) defines the unique name of the configuration and the taint analysis is performed using the predicate ``hasFlow(DataFlow::Node source, DataFlow::Node sink)``. @@ -214,7 +219,7 @@ The class ``RemoteSourceFlow`` (defined in module ``semmle.code.csharp.dataflow. Example ~~~~~~~ -The following example shows a data flow configuration that uses all public API parameters as data sources. +This query shows a data flow configuration that uses all public API parameters as data sources: .. code-block:: ql @@ -236,30 +241,30 @@ The following example shows a data flow configuration that uses all public API p Class hierarchy ~~~~~~~~~~~~~~~ -- ``DataFlow::Configuration`` - base class for custom global data flow analysis -- ``DataFlow::Node`` - an element behaving as a data flow node +- ``DataFlow::Configuration`` - base class for custom global data flow analysis. +- ``DataFlow::Node`` - an element behaving as a data flow node. - - ``DataFlow::ExprNode`` - an expression behaving as a data flow node - - ``DataFlow::ParameterNode`` - a parameter data flow node representing the value of a parameter at function entry + - ``DataFlow::ExprNode`` - an expression behaving as a data flow node. + - ``DataFlow::ParameterNode`` - a parameter data flow node representing the value of a parameter at function entry. - - ``PublicCallableParameter`` - a parameter to a public method/callable in a public class + - ``PublicCallableParameter`` - a parameter to a public method/callable in a public class. - - ``RemoteSourceFlow`` - data flow from network/remote input + - ``RemoteSourceFlow`` - data flow from network/remote input. - - ``AspNetRemoteFlowSource`` - data flow from remote ASP.NET user input + - ``AspNetRemoteFlowSource`` - data flow from remote ASP.NET user input. - - ``AspNetQueryStringRemoteFlowSource`` - data flow from ``System.Web.HttpRequest`` - - ``AspNetUserInputRemoveFlowSource`` - data flow from ``System.Web.IO.WebControls.TextBox`` + - ``AspNetQueryStringRemoteFlowSource`` - data flow from ``System.Web.HttpRequest``. + - ``AspNetUserInputRemoveFlowSource`` - data flow from ``System.Web.IO.WebControls.TextBox``. - - ``WcfRemoteFlowSource`` - data flow from a WCF web service - - ``AspNetServiceRemoteFlowSource`` - data flow from an ASP.NET web service + - ``WcfRemoteFlowSource`` - data flow from a WCF web service. + - ``AspNetServiceRemoteFlowSource`` - data flow from an ASP.NET web service. -- ``TaintTracking::Configuration`` - base class for custom global taint tracking analysis +- ``TaintTracking::Configuration`` - base class for custom global taint tracking analysis. Examples ~~~~~~~~ -The following data flow configuration tracks data flow from environment variables to opening files: +This data flow configuration tracks data flow from environment variables to opening files: .. code-block:: ql @@ -300,7 +305,7 @@ Exercise 4: Using the answers from 2 and 3, write a query to find all global dat Extending library data flow --------------------------- -*Library* data flow defines how data flows through libraries where the source code is not available, such as the .NET Framework, third-party libraries or proprietary libraries. +Library data flow defines how data flows through libraries where the source code is not available, such as the .NET Framework, third-party libraries or proprietary libraries. To define new library data flow, extend the class ``LibraryTypeDataFlow`` from the module ``semmle.code.csharp.dataflow.LibraryTypeDataFlow``. Override the predicate ``callableFlow`` to define how data flows through the methods in the class. ``callableFlow`` has the signature @@ -308,9 +313,9 @@ To define new library data flow, extend the class ``LibraryTypeDataFlow`` from t predicate callableFlow(CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable callable, boolean preservesValue) -- ``callable`` - the ``Callable`` (such as a method, constructor, property getter or setter) performing the data flow -- ``source`` - the data flow input -- ``sink`` - the data flow output +- ``callable`` - the ``Callable`` (such as a method, constructor, property getter or setter) performing the data flow. +- ``source`` - the data flow input. +- ``sink`` - the data flow output. - ``preservesValue`` - whether the flow step preserves the value, for example if ``x`` is a string then ``x.ToString()`` preserves the value where as ``x.ToLower()`` does not. Class hierarchy @@ -318,24 +323,24 @@ Class hierarchy - ``Callable`` - a callable (methods, accessors, constructors etc.) - - ``SourceDeclarationCallable`` - an unconstructed callable + - ``SourceDeclarationCallable`` - an unconstructed callable. -- ``CallableFlowSource`` - the input of data flow into the callable +- ``CallableFlowSource`` - the input of data flow into the callable. - - ``CallableFlowSourceQualifier`` - the data flow comes from the object itself - - ``CallableFlowSourceArg`` - the data flow comes from an argument to the call + - ``CallableFlowSourceQualifier`` - the data flow comes from the object itself. + - ``CallableFlowSourceArg`` - the data flow comes from an argument to the call. -- ``CallableFlowSink`` - the output of data flow from the callable +- ``CallableFlowSink`` - the output of data flow from the callable. - - ``CallableFlowSinkQualifier`` - the output is to the object itself - - ``CallableFlowSinkReturn`` - the output is returned from the call - - ``CallableFlowSinkArg`` - the output is an argument - - ``CallableFlowSinkDelegateArg`` - the output flows through a delegate argument (for example, LINQ) + - ``CallableFlowSinkQualifier`` - the output is to the object itself. + - ``CallableFlowSinkReturn`` - the output is returned from the call. + - ``CallableFlowSinkArg`` - the output is an argument. + - ``CallableFlowSinkDelegateArg`` - the output flows through a delegate argument (for example, LINQ). Example ~~~~~~~ -The following example is adapted from ``LibraryTypeDataFlow.qll``. It declares data flow through the class ``System.Uri``, including the constructor, the ``ToString`` method, and the properties ``Query``, ``OriginalString``, and ``PathAndQuery``. +This example is adapted from ``LibraryTypeDataFlow.qll``. It declares data flow through the class ``System.Uri``, including the constructor, the ``ToString`` method, and the properties ``Query``, ``OriginalString``, and ``PathAndQuery``. .. code-block:: ql @@ -489,7 +494,7 @@ Exercise 4 Exercise 5 ~~~~~~~~~~ -All properties can flow data. We can declare this as follows: +All properties can flow data: .. code-block:: ql @@ -545,9 +550,9 @@ This can be adapted from the ``SystemUriFlow`` class: } } -What next? ----------- +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 handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- Find out more about QL in the `QL language reference `__. +- Learn more about the query console in `Using the query console `__ on LGTM.com. diff --git a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst index 32a782d5034..f262478dc44 100644 --- a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst +++ b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst @@ -1,18 +1,20 @@ -Introducing the CodeQL libraries for C# -======================================= +CodeQL library for C# +===================== -Overview --------- +When you're analyzing a C# program, you can make use of the large collection of classes in the CodeQL library for C#. -There is an extensive library for analyzing CodeQL databases extracted from C# projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``csharp.qll`` imports all the core C# library modules, so you can include the complete library by beginning your query with: +About the CodeQL libraries for C# +--------------------------------- + +There is an extensive core library for analyzing CodeQL databases extracted from C# projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``csharp.qll`` imports all the core C# library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import csharp -Since this is required for all C# queries, it is omitted from code snippets below. +Since this is required for all C# queries, it's omitted from code snippets below. -The core library contains all the program elements, including `files <#files>`__, `types <#types>`__, methods, `variables <#variables>`__, `statements <#statements>`__, and `expressions <#expressions>`__. This is sufficient for most queries, however additional libraries can be imported for bespoke functionality such as control flow and data flow. See :doc:`CodeQL for C# ` for information about these additional libraries. +The core library contains all the program elements, including `files <#files>`__, `types <#types>`__, methods, `variables <#variables>`__, `statements <#statements>`__, and `expressions <#expressions>`__. This is sufficient for most queries, however additional libraries can be imported for bespoke functionality such as control flow and data flow. For information about these additional libraries, see :doc:`CodeQL for C# `. Class hierarchies ~~~~~~~~~~~~~~~~~ @@ -42,7 +44,7 @@ Each section contains a class hierarchy, showing the inheritance structure betwe - ``AddExpr``, ``SubExpr``, ``MulExpr``, ``DivExpr``, ``RemExpr`` -This means that the class ``AddExpr`` extends class ``BinaryArithmeticOperation``, which in turn extends class ``ArithmeticOperation`` and so on. If you want to query any arithmetic operation, then use the class ``ArithmeticOperation``, but if you specifically want to limit the query to addition operations, then use the class ``AddExpr``. +This means that the class ``AddExpr`` extends class ``BinaryArithmeticOperation``, which in turn extends class ``ArithmeticOperation`` and so on. If you want to query any arithmetic operation, use the class ``ArithmeticOperation``, but if you specifically want to limit the query to addition operations, use the class ``AddExpr``. Classes can also be considered to be *sets*, and the ``extends`` relation between classes defines a subset. Every member of class ``AddExpr`` is also in the class ``BinaryArithmeticOperation``. In general, classes overlap and an entity can be a member of several classes. @@ -50,14 +52,14 @@ This overview omits some of the less important or intermediate classes from the Each class has predicates, which are logical propositions about that class. They also define navigable relationships between classes. Predicates are inherited, so for example the ``AddExpr`` class inherits the predicates ``getLeftOperand()`` and ``getRightOperand()`` from ``BinaryArithmeticOperation``, and ``getType()`` from class ``Expr``. This is similar to how methods are inherited in object-oriented programming languages. -In this overview, we present the most common and useful predicates. Consult the `reference `__, the CodeQL source code, and autocomplete in the editor for the complete list of predicates available on each class. +In this overview, we present the most common and useful predicates. For the complete list of predicates available on each class, you can look in the CodeQL source code, use autocomplete in the editor, or see the `C# reference `__. Exercises ~~~~~~~~~ Each section in this topic contains exercises to check your understanding. -Exercise 1: Simplify the following query: +Exercise 1: Simplify this query: .. code-block:: ql @@ -84,11 +86,11 @@ Class hierarchy Predicates ~~~~~~~~~~ -- ``getName()`` - gets the full path of the file (for example, ``C:\Temp\test.cs``) -- ``getNumberOfLines()`` - gets the number of lines (for source files only) -- ``getShortName()`` - gets the name of the file without the extension (for example, ``test``) -- ``getBaseName()`` - gets the name and extension of the file (for example, ``test.cs``) -- ``getParent()`` - gets the parent directory +- ``getName()`` - gets the full path of the file (for example, ``C:\Temp\test.cs``). +- ``getNumberOfLines()`` - gets the number of lines (for source files only). +- ``getShortName()`` - gets the name of the file without the extension (for example, ``test``). +- ``getBaseName()`` - gets the name and extension of the file (for example, ``test.cs``). +- ``getParent()`` - gets the parent directory. Examples ~~~~~~~~ @@ -116,7 +118,7 @@ Exercise 2: Write a query to find the source file with the largest number of lin Elements -------- -The class `Element `__ is the base class for all parts of a C# program, and it is the root of the element class hierarchy. All program elements (such as types, methods, statements, and expressions) ultimately derive from this common base class. +The class `Element `__ is the base class for all parts of a C# program, and it's the root of the element class hierarchy. All program elements (such as types, methods, statements, and expressions) ultimately derive from this common base class. ``Element`` forms a hierarchical structure of the program, which can be navigated using the ``getParent()`` and ``getChild()`` predicates. This is much like an abstract syntax tree, and also applies to elements in assemblies. @@ -125,10 +127,10 @@ Predicates The ``Element`` class provides common functionality for all program elements, including: -- ``getLocation()`` - gets the text span in the source code -- ``getFile()`` - gets the ``File`` containing the ``Element`` -- ``getParent()`` - gets the parent ``Element``, if any -- ``getAChild()`` - gets a child ``Element`` of this element, if any +- ``getLocation()`` - gets the text span in the source code. +- ``getFile()`` - gets the ``File`` containing the ``Element``. +- ``getParent()`` - gets the parent ``Element``, if any. +- ``getAChild()`` - gets a child ``Element`` of this element, if any. Examples ~~~~~~~~ @@ -163,11 +165,11 @@ Predicates Some predicates of ``Location`` include: -- ``getFile()`` - gets the ``File`` -- ``getStartLine()`` - gets the first line of the text -- ``getEndLine()`` - gets the last line of the text -- ``getStartColumn()`` - gets the column of the start of the text -- ``getEndColumn()`` - gets the column of the end of the text +- ``getFile()`` - gets the ``File``. +- ``getStartLine()`` - gets the first line of the text. +- ``getEndLine()`` - gets the last line of the text. +- ``getStartColumn()`` - gets the column of the start of the text. +- ``getEndColumn()`` - gets the column of the end of the text. Examples ~~~~~~~~ @@ -213,10 +215,10 @@ Predicates Useful member predicates on ``Declaration`` include: -- ``getDeclaringType()`` - gets the type containing the declaration, if any -- ``getName()``/``hasName(string)`` - gets the name of the declared entity -- ``isSourceDeclaration()`` - whether the declaration is source code and is not a constructed type/method -- ``getSourceDeclaration()`` - gets the original (unconstructed) declaration +- ``getDeclaringType()`` - gets the type containing the declaration, if any. +- ``getName()``/``hasName(string)`` - gets the name of the declared entity. +- ``isSourceDeclaration()`` - whether the declaration is source code and is not a constructed type/method. +- ``getSourceDeclaration()`` - gets the original (unconstructed) declaration. Examples ~~~~~~~~ @@ -262,10 +264,10 @@ Predicates Some common predicates on ``Variable`` are: -- ``getType()`` - gets the ``Type`` of this variable -- ``getAnAccess()`` - gets an expression that accesses (reads or writes) this variable, if any -- ``getAnAssignedValue()`` - gets an expression that is assigned to this variable, if any -- ``getInitializer()`` - gets the expression used to initialize the variable, if any +- ``getType()`` - gets the ``Type`` of this variable. +- ``getAnAccess()`` - gets an expression that accesses (reads or writes) this variable, if any. +- ``getAnAssignedValue()`` - gets an expression that is assigned to this variable, if any. +- ``getInitializer()`` - gets the expression used to initialize the variable, if any. Examples ~~~~~~~~ @@ -309,7 +311,7 @@ Class hierarchy - ``VoidType`` - ``void`` - ``PointerType`` - a pointer type -The ``ValueType`` class extends further as follows: +The ``ValueType`` class extends further: - ``ValueType`` - a value type @@ -345,7 +347,7 @@ The ``ValueType`` class extends further as follows: - ``NullableType`` - ``ArrayType`` -The ``RefType`` class extends further as follows: +The ``RefType`` class extends further: - ``RefType`` @@ -369,19 +371,19 @@ Predicates Useful members of ``ValueOrRefType`` include: -- ``getQualifiedName()/hasQualifiedName(string)`` - gets the qualified name of the type (for example, ``"System.String"``) -- ``getABaseInterface()`` - gets an immediate interface of this type, if any -- ``getABaseType()`` - gets an immediate base class or interface of this type, if any -- ``getBaseClass()`` - gets the immediate base class of this type, if any -- ``getASubType()`` - gets an immediate subtype, a type which directly inherits from this type, if any -- ``getAMember()`` - gets any member (field/method/property etc), if any -- ``getAMethod()`` - gets a method, if any -- ``getAProperty()`` - gets a property, if any -- ``getAnIndexer()`` - gets an indexer, if any -- ``getAnEvent()`` - gets an event, if any -- ``getAnOperator()`` - gets an operator, if any -- ``getANestedType()`` - gets a nested type -- ``getNamespace()`` - gets the enclosing namespace +- ``getQualifiedName()/hasQualifiedName(string)`` - gets the qualified name of the type (for example, ``"System.String"``). +- ``getABaseInterface()`` - gets an immediate interface of this type, if any. +- ``getABaseType()`` - gets an immediate base class or interface of this type, if any. +- ``getBaseClass()`` - gets the immediate base class of this type, if any. +- ``getASubType()`` - gets an immediate subtype, a type which directly inherits from this type, if any. +- ``getAMember()`` - gets any member (field/method/property etc), if any. +- ``getAMethod()`` - gets a method, if any. +- ``getAProperty()`` - gets a property, if any. +- ``getAnIndexer()`` - gets an indexer, if any. +- ``getAnEvent()`` - gets an event, if any. +- ``getAnOperator()`` - gets an operator, if any. +- ``getANestedType()`` - gets a nested type. +- ``getNamespace()`` - gets the enclosing namespace. Examples ~~~~~~~~ @@ -492,12 +494,12 @@ Predicates Here are a few useful predicates on the ``Callable`` class: -- ``getParameter(int)``/``getAParameter()`` - gets a parameter -- ``calls(Callable)`` - whether there's a direct call from one callable to another -- ``getReturnType()`` - gets the return type -- ``getBody()``/``getExpressionBody()`` - gets the body of the callable +- ``getParameter(int)``/``getAParameter()`` - gets a parameter. +- ``calls(Callable)`` - whether there's a direct call from one callable to another. +- ``getReturnType()`` - gets the return type. +- ``getBody()``/``getExpressionBody()`` - gets the body of the callable. -Since ``Callable`` extends ``Declaration``, it also has predicates from ``Declaration``, such as +Since ``Callable`` extends ``Declaration``, it also has predicates from ``Declaration``, such as: - ``getName()``/``hasName(string)`` - ``getSourceDeclaration()`` @@ -506,10 +508,10 @@ Since ``Callable`` extends ``Declaration``, it also has predicates from ``Declar Methods have additional predicates, including: -- ``getAnOverridee()`` - gets a method that is immediately overridden by this method -- ``getAnOverrider()`` - gets a method that immediately overrides this method -- ``getAnImplementee()`` - gets an interface method that is immediately implemented by this method -- ``getAnImplementor()`` - gets a method that immediately implements this interface method +- ``getAnOverridee()`` - gets a method that is immediately overridden by this method. +- ``getAnOverrider()`` - gets a method that immediately overrides this method. +- ``getAnImplementee()`` - gets an interface method that is immediately implemented by this method. +- ``getAnImplementor()`` - gets a method that immediately implements this interface method. Examples ~~~~~~~~ @@ -665,7 +667,7 @@ Find an ``if`` statement with a constant condition: where ifStmt.getCondition().hasValue() select ifStmt, "This 'if' statement is constant." -Find an ``if`` statement with an empty "then" clause: +Find an ``if`` statement with an empty "then" block: .. code-block:: ql @@ -680,7 +682,7 @@ Exercises Exercise 6: Write a query to list all empty methods. (`Answer <#exercise-6>`__) -Exercise 7: Modify the last example to also detect empty statements (``;``) in the then block. (`Answer <#exercise-7>`__) +Exercise 7: Modify the last example to also detect empty statements (``;``) in the "then" block. (`Answer <#exercise-7>`__) Exercise 8: Modify the last example to exclude chains of ``if`` statements, where the ``else`` part is another ``if`` statement. (`Answer <#exercise-8>`__) @@ -874,13 +876,13 @@ Predicates Useful predicates on ``Expr`` include: -- ``getType()`` - gets the ``Type`` of the expression -- ``getValue()`` - gets the compile-time constant, if any -- ``hasValue()`` - whether the expression has a compile-time constant -- ``getEnclosingStmt()`` - gets the statement containing the expression, if any -- ``getEnclosingCallable()`` - gets the callable containing the expression, if any -- ``stripCasts()`` - remove all explicit or implicit casts -- ``isImplicit()`` - whether the expression was implicit, such as an implicit ``this`` qualifier (``ThisAccess``) +- ``getType()`` - gets the ``Type`` of the expression. +- ``getValue()`` - gets the compile-time constant, if any. +- ``hasValue()`` - whether the expression has a compile-time constant. +- ``getEnclosingStmt()`` - gets the statement containing the expression, if any. +- ``getEnclosingCallable()`` - gets the callable containing the expression, if any. +- ``stripCasts()`` - remove all explicit or implicit casts. +- ``isImplicit()`` - whether the expression was implicit, such as an implicit ``this`` qualifier (``ThisAccess``). Examples ~~~~~~~~ @@ -922,7 +924,7 @@ Attributes C# attributes are represented by the class `Attribute `__. They can be present on many C# elements, such as classes, methods, fields, and parameters. The database contains attributes from the source code and all assembly references. -The attribute of any ``Element`` can be obtained via ``getAnAttribute()``, whereas if you have an attribute, you can find its element via ``getTarget()``. The following two query fragments are identical: +The attribute of any ``Element`` can be obtained via ``getAnAttribute()``, whereas if you have an attribute, you can find its element via ``getTarget()``. These two query fragments are identical: .. code-block:: ql @@ -939,8 +941,8 @@ Class hierarchy Predicates ~~~~~~~~~~ -- ``getTarget()`` - gets the ``Element`` to which this attribute applies -- ``getArgument(int)`` - gets the given argument of the attribute +- ``getTarget()`` - gets the ``Element`` to which this attribute applies. +- ``getArgument(int)`` - gets the given argument of the attribute. - ``getType()`` - gets the type of this attribute. Note that the class name must end in ``"Attribute"``. Examples @@ -1117,9 +1119,9 @@ Here is the fixed version: else reason = "(not given)" select e, "This is obsolete because " + reason -What next? ----------- +Further reading +--------------- -- Visit :doc:`Tutorial: 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 handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. \ No newline at end of file +- 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. diff --git a/docs/language/learn-ql/csharp/ql-for-csharp.rst b/docs/language/learn-ql/csharp/ql-for-csharp.rst index bc5cc9e9959..6eb3567e808 100644 --- a/docs/language/learn-ql/csharp/ql-for-csharp.rst +++ b/docs/language/learn-ql/csharp/ql-for-csharp.rst @@ -1,27 +1,21 @@ CodeQL for C# ============= +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from C# codebases. + .. toctree:: - :glob: :hidden: introduce-libraries-csharp dataflow -These topics provide an overview of the CodeQL libraries for C# and show examples of how to use them. +- `Basic C# query `__: Learn to write and run a simple CodeQL query using LGTM. -- `Basic C# query `__ describes how to write and run queries using LGTM. +- :doc:`CodeQL library for C# `: When you're analyzing a C# program, you can make use of the large collection of classes in the CodeQL library for C#. -- :doc:`Introducing the CodeQL libraries for C# ` introduces the standard libraries used to write queries for C# code. +- :doc:`Analyzing data flow in C# `: You can use CodeQL to track the flow of data through a C# program to its use. -.. raw:: html - - - -- :doc:`Tutorial: Analyzing data flow in C# ` demonstrates how to write queries using the standard data flow and taint tracking libraries for C#. - - -Other resources +Further reading --------------- - For examples of how to query common C# elements, see the `C# cookbook `__. diff --git a/docs/language/learn-ql/database.rst b/docs/language/learn-ql/database.rst deleted file mode 100644 index fe8e2e273ef..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 `__. - -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.dot b/docs/language/learn-ql/go/ast.dot new file mode 100644 index 00000000000..fbf32b744ed --- /dev/null +++ b/docs/language/learn-ql/go/ast.dot @@ -0,0 +1,22 @@ +digraph ast { + graph [dpi=300]; + "x" [shape=rect]; + "y" [shape=rect]; + "x + y" [shape=rect]; + "(x + y)" [shape=rect]; + "z" [shape=rect]; + "(x + y) * z" [shape=rect]; + invis1 [style=invis]; + invis2 [style=invis]; + invis3 [style=invis]; + + "(x + y) * z" -> "(x + y)" [label=" 0"]; + "(x + y) * z" -> "z" [label=" 1"]; + "(x + y)" -> "x + y" [label=" 0"]; + "x + y" -> "x" [label=" 0"]; + "x + y" -> "y" [label=" 1"]; + + "z" -> invis1 [style=invis]; + invis1 -> invis2 [style=invis]; + invis1 -> invis3 [style=invis]; +} diff --git a/docs/language/learn-ql/go/ast.png b/docs/language/learn-ql/go/ast.png new file mode 100644 index 00000000000..61a9f29b80a Binary files /dev/null and b/docs/language/learn-ql/go/ast.png differ diff --git a/docs/language/learn-ql/go/cfg.dot b/docs/language/learn-ql/go/cfg.dot new file mode 100644 index 00000000000..47db3df4c57 --- /dev/null +++ b/docs/language/learn-ql/go/cfg.dot @@ -0,0 +1,8 @@ +digraph cfg { + graph [dpi=300]; + rankdir=LR; + "x := 0" -> "p != nil"; + "p != nil" -> "x = p.f"; + "p != nil" -> "return x"; + "x = p.f" -> "return x"; +} diff --git a/docs/language/learn-ql/go/cfg.png b/docs/language/learn-ql/go/cfg.png new file mode 100644 index 00000000000..1290dadb870 Binary files /dev/null and b/docs/language/learn-ql/go/cfg.png differ diff --git a/docs/language/learn-ql/go/cfg2.dot b/docs/language/learn-ql/go/cfg2.dot new file mode 100644 index 00000000000..b8dcd71ee25 --- /dev/null +++ b/docs/language/learn-ql/go/cfg2.dot @@ -0,0 +1,14 @@ +digraph cfg2 { + graph [dpi=300]; + rankdir=LR; + + "p != nil is true" [shape=box]; + "p != nil is false" [shape=box]; + + "x := 0" -> "p != nil"; + "p != nil" -> "p != nil is true"; + "p != nil is true" -> "x = p.f"; + "p != nil" -> "p != nil is false"; + "p != nil is false" -> "return x"; + "x = p.f" -> "return x"; +} diff --git a/docs/language/learn-ql/go/cfg2.png b/docs/language/learn-ql/go/cfg2.png new file mode 100644 index 00000000000..617fe4fe4dc Binary files /dev/null and b/docs/language/learn-ql/go/cfg2.png differ diff --git a/docs/language/learn-ql/go/dfg.dot b/docs/language/learn-ql/go/dfg.dot new file mode 100644 index 00000000000..82253c9b133 --- /dev/null +++ b/docs/language/learn-ql/go/dfg.dot @@ -0,0 +1,11 @@ +digraph dfg { + graph [dpi=300]; + rankdir=LR; + + "x" [shape=diamond]; + "return x" [label=x>]; + + "0" -> "x"; + "p.f" -> "x"; + "x" -> "return x"; +} diff --git a/docs/language/learn-ql/go/dfg.png b/docs/language/learn-ql/go/dfg.png new file mode 100644 index 00000000000..6727af7b4ac Binary files /dev/null and b/docs/language/learn-ql/go/dfg.png differ diff --git a/docs/language/learn-ql/go/introduce-libraries-go.rst b/docs/language/learn-ql/go/introduce-libraries-go.rst new file mode 100644 index 00000000000..e47ce2b94c4 --- /dev/null +++ b/docs/language/learn-ql/go/introduce-libraries-go.rst @@ -0,0 +1,621 @@ +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. + +Overview +-------- + +CodeQL ships with an extensive library for analyzing Go code. The classes in this library present +the data from a CodeQL database in an object-oriented form and provide abstractions and predicates +to help you with common analysis tasks. + +The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The +module ``go.qll`` imports most other standard library modules, so you can include the complete +library by beginning your query with: + +.. code-block:: ql + + import go + +Broadly speaking, the CodeQL library for Go provides two views of a Go code base: at the `syntactic +level`, source code is represented as an `abstract syntax tree +`__ (AST), while at the `data-flow level` it is +represented as a `data-flow graph `__ (DFG). In +between, there is also an intermediate representation of the program as a control-flow graph (CFG), +though this representation is rarely useful on its own and mostly used to construct the higher-level +DFG representation. + +The AST representation captures the syntactic structure of the program. You can use it to reason +about syntactic properties such as the nesting of statements within each other, but also about the +types of expressions and which variable a name refers to. + +The DFG, on the other hand, provides an approximation of how data flows through variables and +operations at runtime. It is used, for example, by the security queries to model the way +user-controlled input can propagate through the program. Additionally, the DFG contains information +about which function may be invoked by a given call (taking virtual dispatch through interfaces into +account), as well as control-flow information about the order in which different operations may be +executed at runtime. + +As a rule of thumb, you normally want to use the AST only for superficial syntactic queries. Any +analysis involving deeper semantic properties of the program should be done on the DFG. + +The rest of this tutorial briefly summarizes the most important classes and predicates provided by +this library, including references to the `detailed API documentation +`__ where applicable. We start by giving an overview of the AST +representation, followed by an explanation of names and entities, which are used to represent +name-binding information, and of types and type information. Then we move on to control flow and the +data-flow graph, and finally the call graph and a few advanced topics. + +Abstract syntax +--------------- + +The AST presents the program as a hierarchical structure of nodes, each of which corresponds to a +syntactic element of the program source text. For example, there is an AST node for each expression +and each statement in the program. These AST nodes are arranged into a parent-child relationship +reflecting the nesting of syntactic elements and the order in which inner elements appear in +enclosing ones. + +For example, this is the AST for the expression ``(x + y) * z``: + +|ast| + +It is composed of six AST nodes, representing ``x``, ``y``, ``x + y``, ``(x + y)``, ``z`` and the +entire expression ``(x + y) * z``, respectively. The AST nodes representing ``x`` and ``y`` are +children of the AST node representing ``x + y``, ``x`` being the zeroth child and ``y`` being the +first child, reflecting their order in the program text. Similarly, ``x + y`` is the only child of +``(x + y)``, which is the zeroth child of ``(x + y) * z``, whose first child is ``z``. + +All AST nodes belong to class `AstNode +`__, which defines generic +tree traversal predicates: + +- ``getChild(i)``: returns the ``i``\ th child of this AST node. +- ``getAChild()``: returns any child of this AST node. +- ``getParent()``: returns the parent node of this AST node, if any. + +These predicates should only be used to perform generic AST traversal. To access children of +specific AST node types, the specialized predicates introduced below should be used instead. In +particular, queries should not rely on the numeric indices of child nodes relative to their parent +nodes: these are considered an implementation detail that may change between versions of the +library. + +The predicate ``toString()`` in class ``AstNode`` nodes gives a short description of the AST node, +usually just indicating what kind of node it is. The ``toString()`` predicate does `not` provide +access to the source text corresponding to an AST node. The source text is not stored in the +dataset, and hence is not directly accessible to CodeQL queries. + +The predicate ``getLocation()`` in class ``AstNode`` returns a `Location +`__ entity +describing the source location of the program element represented by the AST node. You can use its +member predicates ``getFile()``, ``getStartLine()``, ``getStartColumn``, ``getEndLine()``, and +``getEndColumn()`` to obtain information about its file, start line and column, and end line and +column. + +The most important subclasses of `AstNode +`__ are `Stmt +`__ and `Expr +`__, which represent +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 +`__. + +Statements +~~~~~~~~~~ + +- ``ExprStmt``: an expression statement; use ``getExpr()`` to access the expression itself +- ``Assignment``: an assignment statement; use ``getLhs(i)`` to access the ``i``\ th left-hand side + and ``getRhs(i)`` to access the ``i``\ th right-hand side; if there is only a single left-hand side + you can use ``getLhs()`` instead, and similar for the right-hand side + + - ``SimpleAssignStmt``: an assignment statement that does not involve a compound operator + + - ``AssignStmt``: a plain assignment statement of the form ``lhs = rhs`` + - ``DefineStmt``: a short-hand variable declaration of the form ``lhs := rhs`` + + - ``CompoundAssignStmt``: an assignment statement with a compound operator, such as ``lhs += rhs`` + +- ``IncStmt``, ``DecStmt``: an increment statement or a decrement statement, respectively; use + ``getOperand()`` to access the expression being incremented or decremented +- ``BlockStmt``: a block of statements between curly braces; use ``getStmt(i)`` to access the + ``i``\ th statement in a block +- ``IfStmt``: an ``if`` statement; use ``getInit()``, ``getCond()``, ``getThen()``, and + ``getElse()`` to access the (optional) init statement, the condition being checked, the "then" + branch to evaluate if the condition is true, and the (optional) "else" branch to evaluate + otherwise, respectively +- ``LoopStmt``: a loop; use ``getBody()`` to access its body + + - ``ForStmt``: a ``for`` statement; use ``getInit()``, ``getCond()``, and ``getPost()`` to access + the init statement, loop condition, and post statement, respectively, all of which are optional + + - ``RangeStmt``: a ``range`` statement; use ``getDomain()`` to access the iteration domain, and + ``getKey()`` and ``getValue()`` to access the expressions to which successive keys and values + are assigned, if any + +- ``GoStmt``: a ``go`` statement; use ``getCall()`` to access the call expression that is evaluated + in the new goroutine +- ``DeferStmt``: a ``defer`` statement; use ``getCall()`` to access the call expression being + deferred +- ``SendStmt``: a send statement; use ``getChannel()`` and ``getValue()`` to access the channel and + the value being sent over the channel, respectively +- ``ReturnStmt``: a ``return`` statement; use ``getExpr(i)`` to access the ``i``\ th returned + expression; if there is only a single returned expression you can use ``getExpr()`` instead +- ``BranchStmt``: a statement that interrupts structured control flow; use ``getLabel()`` to get the + optional target label + + - ``BreakStmt``: a ``break`` statement + - ``ContinueStmt``: a ``continue`` statement + - ``FallthroughStmt``: a ``fallthrough`` statement at the end of a switch case + - ``GotoStmt``: a ``goto`` statement + +- ``DeclStmt``: a declaration statement, use ``getDecl()`` to access the declaration in this + statement; note that one rarely needs to deal with declaration statements directly, since + reasoning about the entities they declare is usually easier +- ``SwitchStmt``: a ``switch`` statement; use ``getInit()`` to access the (optional) init statement, + and ``getCase(i)`` to access the ``i``\ th ``case`` or ``default`` clause + + - ``ExpressionSwitchStmt``: a ``switch`` statement examining the value of an expression + - ``TypeSwitchStmt``: a ``switch`` statement examining the type of an expression + +- ``CaseClause``: a ``case`` or ``default`` clause in a ``switch`` statement; use ``getExpr(i)`` to + access the ``i``\ th expression, and ``getStmt(i)`` to access the ``i``\ th statement in the body + of this clause +- ``SelectStmt``: a ``select`` statement; use ``getCommClause(i)`` to access the ``i``\ th ``case`` + or ``default`` clause +- ``CommClause``: a ``case`` or ``default`` clause in a ``select`` statement; use ``getComm()`` to + access the send/receive statement of this clause (not defined for ``default`` clauses), and + ``getStmt(i)`` to access the ``i``\ th statement in the body of this clause +- ``RecvStmt``: a receive statement in a ``case`` clause of a ``select`` statement; use + ``getLhs(i)`` to access the ``i``\ th left-hand side of this statement, and ``getExpr()`` to + access the underlying receive expression + +Expressions +~~~~~~~~~~~ + +Class ``Expression`` has a predicate ``isConst()`` that holds if the expression is a compile-time +constant. For such constant expressions, ``getNumericValue()`` and ``getStringValue()`` can be used +to determine their numeric value and string value, respectively. Note that these predicates are not +defined for expressions whose value cannot be determined at compile time. Also note that the result +type of ``getNumericValue()`` is the QL type ``float``. If an expression has a numeric value that +cannot be represented as a QL ``float``, this predicate is also not defined. In such cases, you can +use ``getExactValue()`` to obtain a string representation of the value of the constant. + +- ``Ident``: an identifier; use ``getName()`` to access its name +- ``SelectorExpr``: a selector of the form ``base.sel``; use ``getBase()`` to access the part before + the dot, and ``getSelector()`` for the identifier after the dot +- ``BasicLit``: a literal of a basic type; subclasses ``IntLit``, ``FloatLit``, ``ImagLit``, + ``RuneLit``, and ``StringLit`` represent various specific kinds of literals +- ``FuncLit``: a function literal; use ``getBody()`` to access the body of the function +- ``CompositeLit``: a composite literal; use ``getKey(i)`` and ``getValue(i)`` to access the + ``i``\ th key and the ``i``\ th value, respectively +- ``ParenExpr``: a parenthesized expression; use ``getExpr()`` to access the expression between the + parentheses +- ``IndexExpr``: an index expression ``base[idx]``; use ``getBase()`` and ``getIndex()`` to access + ``base`` and ``idx``, respectively +- ``SliceExpr``: a slice expression ``base[lo:hi:max]``; use ``getBase()``, ``getLow()``, + ``getHigh()``, and ``getMax()`` to access ``base``, ``lo``, ``hi``, and ``max``, respectively; + note that ``lo``, ``hi``, and ``max`` can be omitted, in which case the corresponding predicates are not defined +- ``ConversionExpr``: a conversion expression ``T(e)``; use ``getTypeExpr()`` and ``getOperand()`` + to access ``T`` and ``e``, respectively +- ``TypeAssertExpr``: a type assertion ``e.(T)``; use ``getExpr()`` and ``getTypeExpr()`` to access + ``e`` and ``T``, respectively +- ``CallExpr``: a call expression ``callee(arg0, ..., argn)``; use ``getCalleeExpr()`` to access + ``callee``, and ``getArg(i)`` to access the ``i``\ th argument +- ``StarExpr``: a star expression, which may be either a pointer-type expression or a + pointer-dereference expression, depending on context; use ``getBase()`` to access the operand of + the star +- ``TypeExpr``: an expression that denotes a type +- ``OperatorExpr``: an expression with a unary or binary operator; use ``getOperator()`` to access + the operator + + - ``UnaryExpr``: an expression with a unary operator; use ``getAnOperand()`` to access the operand + of the operator + - ``BinaryExpr``: an expression with a binary operator; use ``getLeftOperand()`` and + ``getRightOperand()`` to access the left and the right operand, respectively + + - ``ComparisonExpr``: a binary expression that performs a comparison, including both equality + tests and relational comparisons + + - ``EqualityTestExpr``: an equality test, that is, either ``==`` or ``!=``; the predicate + ``getPolarity()`` has result ``true`` for the former and ``false`` for the latter + - ``RelationalComparisonExpr``: a relational comparison; use ``getLesserOperand()`` and + ``getGreaterOperand()`` to access the lesser and greater operand of the comparison, + respectively; ``isStrict()`` holds if this is a strict comparison using ``<`` or ``>``, + as opposed to ``<=`` or ``>=`` + +Names +~~~~~ + +While ``Ident`` and ``SelectorExpr`` are very useful classes, they are often too general: ``Ident`` +covers all identifiers in a program, including both identifiers appearing in a declaration as well +as references, and does not distinguish between names referring to packages, types, variables, +constants, functions, or statement labels. Similarly, a ``SelectorExpr`` might refer to a package, a +type, a function, or a method. + +Class ``Name`` and its subclasses provide a more fine-grained mapping of this space, organized along +the two axes of structure and namespace. In terms of structure, a name can be a ``SimpleName``, +meaning that it is a simple identifier (and hence an ``Ident``), or it can be a ``QualifiedName``, +meaning that it is a qualified identifier (and hence a ``SelectorExpr``). In terms of namespacing, a +``Name`` can be a ``PackageName``, ``TypeName``, ``ValueName``, or ``LabelName``. A ``ValueName``, +in turn, can be either a ``ConstantName``, a ``VariableName``, or a ``FunctionName``, depending on +what sort of entity the name refers to. + +A related abstraction is provided by class ``ReferenceExpr``: a reference expression is an +expression that refers to a variable, a constant, a function, a field, or an element of an array or +a slice. Use predicates ``isLvalue()`` and ``isRvalue()`` to determine whether a reference +expression appears in a syntactic context where it is assigned to or read from, respectively. + +Finally, ``ValueExpr`` generalizes ``ReferenceExpr`` to include all other kinds of expressions that +can be evaluated to a value (as opposed to expressions that refer to a package, a type, or a +statement label). + +Functions +~~~~~~~~~ + +At the syntactic level, functions appear in two forms: in function declarations (represented by +class ``FuncDecl``) and as function literals (represented by class ``FuncLit``). Since it is often +convenient to reason about functions of either kind, these two classes share a common superclass +``FuncDef``, which defines a few useful member predicates: + + - ``getBody()`` provides access to the function body + - ``getName()`` gets the function name; it is undefined for function literals, which do not have a + name + - ``getParameter(i)`` gets the ``i``\ th parameter of the function + - ``getResultVar(i)`` gets the ``i``\ th result variable of the function; if there is only + one result, ``getResultVar()`` can be used to access it + - ``getACall()`` gets a data-flow node (see below) representing a call to this function + +Entities and name binding +------------------------- + +Not all elements of a code base can be represented as AST nodes. For example, functions defined in +the standard library or in a dependency do not have a source-level definition within the source code +of the program itself, and built-in functions like ``len`` do not have a definition at all. Hence +functions cannot simplify be identified with their definition, and similarly for variables, types, +and so on. + +To smooth over this difference and provide a unified view of functions no matter where they are +defined, the Go library introduces the concept of an `entity`. An entity is a named program element, +that is, a package, a type, a constant, a variable, a field, a function, or a label. All entities +belong to class ``Entity``, which defines a few useful predicates: + + - ``getName()`` gets the name of the entity + - ``hasQualifiedName(pkg, n)`` holds if this entity is declared in package ``pkg`` and has name + ``n``; this predicate is only defined for types, functions, and package-level variables and + constants (but not for methods or local variables) + - ``getDeclaration()`` connects an entity to its declaring identifier, if any + - ``getAReference()`` gets a ``Name`` that refers to this entity + +Conversely, class ``Name`` defines a predicate ``getTarget()`` that gets the entity to which the +name refers. + +Class ``Entity`` has several subclasses representing specific kinds of entities: ``PackageEntity`` +for packages; ``TypeEntity`` for types; ``ValueEntity`` for constants (``Constant``), variables +(``Variable``), and functions (``Function``); and ``Label`` for statement labels. + +Class ``Variable``, in turn, has a few subclasses representing specific kinds of variables: a +``LocalVariable`` is a variable declared in a local scope, that is, not at package level; +``ReceiverVariable``, ``Parameter`` and ``ResultVariable`` describe receivers, parameters and +results, respectively, and define a predicate ``getFunction()`` to access the corresponding +function. Finally, class ``Field`` represents struct fields, and provides a member predicate +``hasQualifiedName(pkg, tp, f)`` that holds if this field has name ``f`` and belongs to type ``tp`` +in package ``pkg``. (Note that due to embedding the same field can belong to multiple types.) + +Class ``Function`` has a subclass ``Method`` representing methods (including both interface methods +and methods defined on a named type). Similar to ``Field``, ``Method`` provides a member predicate +``hasQualifiedName(pkg, tp, m)`` that holds if this method has name ``m`` and belongs to type ``tp`` +in package ``pkg``. Predicate ``implements(m2)`` holds if this method implements method ``m2``, that +is, it has the same name and signature as ``m2`` and it belongs to a type that implements the +interface to which ``m2`` belongs. For any function, ``getACall()`` provides access to call sites +that may call this function, possibly through virtual dispatch. + +Finally, module ``Builtin`` provides a convenient way of looking up the entities corresponding to +built-in functions and types. For example, ``Builtin::len()`` is the entity representing the +built-in function ``len``, ``Builtin::bool()`` is the ``bool`` type, and ``Builtin::nil()`` is the +value ``nil``. + +Type information +---------------- + +Types are represented by class ``Type`` and its subclasses, such as ``BoolType`` for the built-in +type ``bool``; ``NumericType`` for the various numeric types including ``IntType``, ``Uint8Type``, +``Float64Type`` and others; ``StringType`` for the type ``string``; ``NamedType``, ``ArrayType``, +``SliceType``, ``StructType``, ``InterfaceType``, ``PointerType``, ``MapType``, ``ChanType`` for +named types, arrays, slices, structs, interfaces, pointers, maps, and channels, respectively. +Finally, ``SignatureType`` represents function types. + +Note that the type ``BoolType`` is distinct from the entity ``Builtin::bool()``: the latter views +``bool`` as a declared entity, the former as a type. You can, however, map from types to their +corresponding entity (if any) using the predicate ``getEntity()``. + +Class ``Expr`` and class ``Entity`` both define a predicate ``getType()`` to determine the type of +an expression or entity. If the type of an expression or entity cannot be determined (for example +because some dependency could not be found during extraction), it will be associated with an invalid +type of class ``InvalidType``. + +Control flow +------------ + +Most CodeQL query writers will rarely use the control-flow representation of a program directly, but +it is nevertheless useful to understand how it works. + +Unlike the abstract syntax tree, which views the program as a hierarchy of AST nodes, the +control-flow graph views it as a collection of `control-flow nodes`, each representing a single +operation performed at runtime. These nodes are connected to each other by (directed) edges +representing the order in which operations are performed. + +For example, consider the following code snippet: + +.. code-block:: go + + x := 0 + if p != nil { + x = p.f + } + return x + +In the AST, this is represented as an ``IfStmt`` and a ``ReturnStmt``, with the former having an +``NeqExpr`` and a ``BlockStmt`` as its children, and so on. This provides a very detailed picture of +the syntactic structure of the code, but it does not immediately help us reason about the order +in which the various operations such as the comparison and the assignment are performed. + +In the CFG, there are nodes corresponding to ``x := 0``, ``p != nil``, ``x = p.f``, and ``return +x``, as well as a few others. The edges between these nodes model the possible execution orders of +these statements and expressions, and look as follows (simplified somewhat for presentational +purposes): + +|cfg| + +For example, the edge from ``p != nil`` to ``x = p.f`` models the case where the comparison +evaluates to ``true`` and the "then" branch is evaluated, while the edge from ``p != nil`` to +``return x`` models the case where the comparison evaluates to ``false`` and the "then" branch is +skipped. + +Note, in particular, that a CFG node can have multiple outgoing edges (like from ``p != nil``) as +well as multiple incoming edges (like into ``return x``) to represent control-flow branching at +runtime. + +Also note that only AST nodes that perform some kind of operation on values have a corresponding CFG +node. This includes expressions (such as the comparison ``p != nil``), assignment statements (such +as ``x = p.f``) and return statements (such as ``return x``), but not statements that serve a purely +syntactic purpose (such as block statements) and statements whose semantics is already reflected by +the CFG edges (such as ``if`` statements). + +It is important to point out that the control-flow graph provided by the CodeQL libraries for Go +only models `local` control flow, that is, flow within a single function. Flow from function calls +to the function they invoke, for example, is not represented by control-flow edges. + +In CodeQL, control-flow nodes are represented by class ``ControlFlow::Node``, and the edges between +nodes are captured by the member predicates ``getASuccessor()`` and ``getAPredecessor()`` of +``ControlFlow::Node``. In addition to control-flow nodes representing runtime operations, each +function also has a synthetic entry node and an exit node, representing the start and end of an +execution of the function, respectively. These exist to ensure that the control-flow graph +corresponding to a function has a unique entry node and a unique exit node, which is required for +many standard control-flow analysis algorithms. + +Data flow +--------- + +At the data-flow level, the program is thought of as a collection of `data-flow nodes`. These nodes +are connected to each other by (directed) edges representing the way data flows through the program +at runtime. + +For example, there are data-flow nodes corresponding to expressions and other data-flow nodes +corresponding to variables (`SSA variables +`__, to be precise). Here is the +data-flow graph corresponding to the code snippet shown above, ignoring SSA conversion for +simplicity: + +|dfg| + +Note that unlike in the control-flow graph, the assignments ``x := 0`` and ``x = p.f`` are not +represented as nodes. Instead, they are expressed as edges between the node representing the +right-hand side of the assignment and the node representing the variable on the left-hand side. For +any subsequent uses of that variable, there is a data-flow edge from the variable to that use, so by +following the edges in the data-flow graph we can trace the flow of values through variables at +runtime. + +It is important to point out that the data-flow graph provided by the CodeQL libraries for Go only +models `local` flow, that is, flow within a single function. Flow from arguments in a function call +to the corresponding function parameters, for example, is not represented by data-flow edges. + +In CodeQL, data-flow nodes are represented by class ``DataFlow::Node``, and the edges between nodes +are captured by the predicate ``DataFlow::localFlowStep``. The predicate ``DataFlow::localFlow`` +generalizes this from a single flow step to zero or more flow steps. + +Most expressions have a corresponding data-flow node; exceptions include type expressions, statement +labels and other expressions that do not have a value, as well as short-circuiting operators. To map +from the AST node of an expression to the corresponding DFG node, use ``DataFlow::exprNode``. Note +that the AST node and the DFG node are different entities and cannot be used interchangeably. + +There is also a predicate ``asExpr()`` on ``DataFlow::Node`` that allows you to recover the +expression underlying a DFG node. However, this predicate should be used with caution, since many +data-flow nodes do not correspond to an expression, and so this predicate will not be defined for +them. + +Similar to ``Expr``, ``DataFlow::Node`` has a member predicate ``getType()`` to determine the type +of a node, as well as predicates ``getNumericValue()``, ``getStringValue()``, and +``getExactValue()`` to retrieve the value of a node if it is constant. + +Important subclasses of ``DataFlow::Node`` include: + + - ``DataFlow::CallNode``: a function call or method call; use ``getArgument(i)`` and + ``getResult(i)`` to obtain the data-flow nodes corresponding to the ``i``\ th argument and the + ``i``\ th result of this call, respectively; if there is only a single result, ``getResult()`` + will return it + - ``DataFlow::ParameterNode``: a parameter of a function; use ``asParameter()`` to access the + corresponding AST node + - ``DataFlow::BinaryOperationNode``: an operation involving a binary operator; each ``BinaryExpr`` + has a corresponding ``BinaryOperationNode``, but there are also binary operations that are not + explicit at the AST level, such as those arising from compound assignments and + increment/decrement statements; at the AST level, ``x + 1``, ``x += 1``, and ``x++`` are + represented by different kinds of AST nodes, while at the DFG level they are all modeled as a + binary operation node with operands ``x`` and ``1`` + - ``DataFlow::UnaryOperationNode``: analogous, but for unary operators + + - ``DataFlow::PointerDereferenceNode``: a pointer dereference, either explicit in an expression + of the form ``*p``, or implicit in a field or method reference through a pointer + - ``DataFlow::AddressOperationNode``: analogous, but for taking the address of an entity + - ``DataFlow::RelationalComparisonNode``, ``DataFlow::EqualityTestNode``: data-flow nodes + corresponding to ``RelationalComparisonExpr`` and ``EqualityTestExpr`` AST nodes + +Finally, classes ``Read`` and ``Write`` represent, respectively, a read or a write of a variable, a +field, or an element of an array, a slice or a map. Use their member predicates ``readsVariable``, +``writesVariable``, ``readsField``, ``writesField``, ``readsElement``, and ``writesElement`` to +determine what the read/write refers to. + +Call graph +---------- + +The call graph connects function (and method) calls to the functions they invoke. Call graph +information is made available by two member predicates on ``DataFlow::CallNode``: ``getTarget()`` +returns the declared target of a call, while ``getACallee()`` returns all possible actual functions +a call may invoke at runtime. + +These two predicates differ in how they handle calls to interface methods: while ``getTarget()`` +will return the interface method itself, ``getACallee()`` will return all concrete methods that +implement the interface method. + +Global data flow and taint tracking +----------------------------------- + +The predicates ``DataFlow::localFlowStep`` and ``DataFlow::localFlow`` are useful for reasoning +about the flow of values in a single function. However, more advanced use cases, particularly in +security analysis, will invariably require reasoning about global data flow, including flow into, +out of, and across function calls, and through fields. + +In CodeQL, such reasoning is expressed in terms of `data-flow configurations`. A data-flow +configuration has three ingredients: sources, sinks, and barriers (also called sanitizers), all of +which are sets of data-flow nodes. Given these three sets, CodeQL provides a general mechanism for +finding paths from a source to a sink, possibly going into and out of functions and fields, but +never flowing through a barrier. + +To define a data-flow configuration, you can define a subclass of ``DataFlow::Configuration``, +overriding the member predicates ``isSource``, ``isSink``, and ``isBarrier`` to define the sets of +sources, sinks, and barriers. + +Going beyond pure data flow, many security analyses need to perform more general `taint tracking`, +which also considers flow through value-transforming operations such as string operations. To track +taint, you can define a subclass of ``TaintTracking::Configuration``, which works similar to +data-flow configurations. + +A detailed exposition of global data flow and taint tracking is out of scope for this brief +introduction. For a general overview of data flow and taint tracking, see `About data flow analysis `__. + +Advanced libraries +------------------ + +Finally, we briefly describe a few concepts and libraries that are useful for advanced query +writers. + +Basic blocks and dominance +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many important control-flow analyses organize control-flow nodes into `basic blocks +`__, which are maximal straight-line sequences of +control-flow nodes without any branching. In the CodeQL libraries, basic blocks are represented by +class ``BasicBlock``. Each control-flow node belongs to a basic block. You can use the predicate +``getBasicBlock()`` in class ``ControlFlow::Node`` and the predicate ``getNode(i)`` in +``BasicBlock`` to move from one to the other. + +Dominance is a standard concept in control-flow analysis: a basic block ``dom`` is said to +`dominate` a basic block ``bb`` if any path through the control-flow graph from the entry node to +the first node of ``bb`` must pass through ``dom``. In other words, whenever program execution +reaches the beginning of ``bb``, it must have come through ``dom``. Each basic block is moreover +considered to dominate itself. + +Dually, a basic block ``postdom`` is said to `post-dominate` a basic block ``bb`` if any path +through the control-flow graph from the last node of ``bb`` to the exit node must pass through +``postdom``. In other words, after program execution leaves ``bb``, it must eventually reach +``postdom``. + +These two concepts are captured by two member predicates ``dominates`` and ``postDominates`` of class +``BasicBlock``. + +Condition guard nodes +~~~~~~~~~~~~~~~~~~~~~ + +A condition guard node is a synthetic control-flow node that records the fact that at some point in +the control-flow graph the truth value of a condition is known. For example, consider again the code snippet we saw above: + +.. code-block:: go + + x := 0 + if p != nil { + x = p.f + } + return x + +At the beginning of the "then" branch ``p`` is known not be ``nil``. This knowledge is encoded in +the control-flow graph by a condition guard node preceding the assignment to ``x``, recording the +fact that ``p != nil`` is ``true`` at this point: + +|cfg2| + +A typical use of this information would be in an analyis that looks for ``nil`` dereferences: such +an analysis would be able to conclude that the field read ``p.f`` is safe because it is immediately +preceded by a condition guard node guaranteeing that ``p`` is not ``nil``. + +In CodeQL, condition guard nodes are represented by class ``ControlFlow::ConditionGuardNode`` which +offers a variety of member predicates to reason about which conditions a guard node guarantees. + +Static single-assignment form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`Static single-assignment form `__ (SSA +form for short) is a program representation in which the original program variables are mapped onto +more fine-grained `SSA variables`. Each SSA variable has exactly one definition, so program +variables with multiple assignments correspond to multiple SSA variables. + +Most of the time query authors do not have to deal with SSA form directly. The data-flow graph uses +it under the hood, and so most of the benefits derived from SSA can be gained by simply using the +data-flow graph. + +For example, the data-flow graph for our running example actually looks more like this: + +|ssa| + +Note that the program variable ``x`` has been mapped onto three distinct SSA variables ``x1``, +``x2``, and ``x3``. In this case there is not much benefit to such a representation, but in general +SSA form has well-known advantages for data-flow analysis for which we refer to the literature. + +If you do need to work with raw SSA variables, they are represented by the class ``SsaVariable``. +Class ``SsaDefinition`` represents definitions of SSA variables, which have a one-to-one +correspondence with ``SsaVariable``\ s. Member predicates ``getDefinition()`` and ``getVariable()`` +exist to map from one to the other. You can use member predicate ``getAUse()`` of ``SsaVariable`` to +look for uses of an SSA variable. To access the program variable underlying an SSA variable, use +member predicate ``getSourceVariable()``. + +Global value numbering +~~~~~~~~~~~~~~~~~~~~~~ + +`Global value numbering `__ is a technique for +determining when two computations in a program are guaranteed to yield the same result. This is done +by associating with each data-flow node an abstract representation of its value (conventionally +called a `value number`, even though in practice it is not usually a number) such that identical +computations are represented by identical value numbers. + +Since this is an undecidable problem, global value numbering is `conservative` in the sense that if +two data-flow nodes have the same value number they are guaranteed to have the same value at +runtime, but not conversely. (That is, there may be data-flow nodes that do, in fact, always +evaluate to the same value, but their value numbers are different.) + +In the CodeQL libraries for Go, you can use the ``globalValueNumber(nd)`` predicate to compute the +global value number for a data-flow node ``nd``. Value numbers are represented as an opaque QL type +``GVN`` that provides very little information. Usually, all you need to do with global value numbers +is to compare them to each other to determine whether two data-flow nodes have the same value. + +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. + +.. |ast| image:: ast.png +.. |cfg| image:: cfg.png +.. |dfg| image:: dfg.png +.. |cfg2| image:: cfg2.png +.. |ssa| image:: ssa.png diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index baa390dc7c6..c977bb6838a 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -1,13 +1,20 @@ CodeQL for Go ============= -This page provides an overview of the CodeQL for Go documentation that is currently available. +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from Go codebases. -- `Basic Go query `__ describes how to write and run queries using LGTM. +.. toctree:: + :hidden: + introduce-libraries-go -Other resources +- `Basic Go query `__: Learn to write and run a simple CodeQL query using LGTM. + +- :doc:`CodeQL library for Go `: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go. + +Further reading --------------- +- For examples of how to query common Go elements, see the `Go cookbook `__. - For the queries used in LGTM, display a `Go query `__ and click **Open in query console** to see the code used to find alerts. - For more information about the library for Go see the `CodeQL library for Go `__. \ No newline at end of file diff --git a/docs/language/learn-ql/go/ssa.dot b/docs/language/learn-ql/go/ssa.dot new file mode 100644 index 00000000000..c8bfb8c62a0 --- /dev/null +++ b/docs/language/learn-ql/go/ssa.dot @@ -0,0 +1,15 @@ +digraph ssa { + graph [dpi=300]; + rankdir=LR; + + "x1" [shape=diamond,label=1>]; + "x2" [shape=diamond,label=2>]; + "x3" [shape=diamond,label=3>]; + "return x" [label=x>]; + + "0" -> "x1"; + "p.f" -> "x2"; + "x1" -> "x3"; + "x2" -> "x3"; + "x3" -> "return x"; +} diff --git a/docs/language/learn-ql/go/ssa.png b/docs/language/learn-ql/go/ssa.png new file mode 100644 index 00000000000..cd5ba3f29de Binary files /dev/null and b/docs/language/learn-ql/go/ssa.png differ diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index 5adafde09e9..0d979f7388a 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -3,8 +3,8 @@ 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. -You can also try out CodeQL in the `query console `__ on `LGTM.com `__. +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. CodeQL is based on a powerful query language called QL. The following topics help you understand QL in general, as well as how to use it when analyzing code with CodeQL. @@ -15,85 +15,25 @@ CodeQL is based on a powerful query language called QL. The following topics hel If you've previously used QL, you may notice slight changes in terms we use to describe some important concepts. For more information, see our note about :doc:`Recent terminology changes `. -.. toctree:: - :hidden: - - terminology-note - - -.. _getting-started: - -Getting started -*************** - -If you are new to QL, start by looking at the following topics: - .. toctree:: :maxdepth: 1 - introduction-to-ql - about-ql beginner/ql-tutorials - ql-etudes/river-crossing - -CodeQL training and variant analysis examples -********************************************* - -To start learning how to use CodeQL for variant analysis for code written in a specific language, see: - -.. toctree:: - :maxdepth: -1 - - ql-training - -.. _writing-ql-queries: - -Writing CodeQL queries -********************** - -To learn more about writing your own queries, see: - -.. toctree:: - :maxdepth: 3 - :includehidden: - writing-queries/writing-queries - -For more information on using CodeQL to query code written in a specific language, see: - -.. toctree:: - :maxdepth: 2 - :includehidden: - cpp/ql-for-cpp csharp/ql-for-csharp go/ql-for-go java/ql-for-java javascript/ql-for-javascript python/ql-for-python - -Technical information -********************* - -For more technical information see: + ql-training .. toctree:: - :maxdepth: 2 - :includehidden: + :hidden: + + terminology-note - technical-info +Further reading +*************** -Reference topics -**************** - -For a more comprehensive guide to the query language itself, see the following reference topics: - -- `QL language handbook `__—a description of important concepts in QL. -- `QL language specification `__—a formal specification of QL. - -Search -****** - -.. * :ref:`genindex` remove index for the time being as we currently have no tags - -* :ref:`search` +- `QL language reference `__: A description of important concepts in QL and a formal specification of the QL language. diff --git a/docs/language/learn-ql/intro-to-data-flow.rst b/docs/language/learn-ql/intro-to-data-flow.rst index f266849dfa7..e509d3a8c16 100644 --- a/docs/language/learn-ql/intro-to-data-flow.rst +++ b/docs/language/learn-ql/intro-to-data-flow.rst @@ -1,10 +1,11 @@ -Introduction to data flow analysis with CodeQL -############################################## +About data flow analysis +######################## + +Data flow analysis is used to compute the possible values that a variable can hold at various points in a program, determining how those values propagate through the program and where they are used. Overview ******** -Data flow analysis computes the possible values that a variable can hold at various points in a program, determining how those values propagate through the program and where they are used. Many CodeQL security queries implement data flow analysis, which can highlight the fate of potentially malicious or insecure data that can cause vulnerabilities in your code base. These queries help you understand if data is used in an insecure way, whether dangerous arguments are passed to functions, or whether sensitive data can leak. As well as highlighting potential security issues, you can also use data flow analysis to understand other aspects of how a program behaves, by finding, for example, uses of uninitialized variables and resource leaks. @@ -17,13 +18,13 @@ See the following tutorials for more information about analyzing data flow in sp - :doc:`Analyzing data flow in C# ` - :doc:`Analyzing data flow in Java ` - :doc:`Analyzing data flow in JavaScript/TypeScript ` -- :doc:`Taint tracking and data flow analysis in Python ` +- :doc:`Analyzing data flow and tracking tainted data in Python ` .. pull-quote:: Note - Data flow analysis is used extensively in path queries. To learn more about path queries, see :doc:`Constructing path queries `. + Data flow analysis is used extensively in path queries. To learn more about path queries, see :doc:`Creating path queries `. .. _data-flow-graph: diff --git a/docs/language/learn-ql/introduction-to-ql.rst b/docs/language/learn-ql/introduction-to-ql.rst index 4945d713803..9deb7523661 100644 --- a/docs/language/learn-ql/introduction-to-ql.rst +++ b/docs/language/learn-ql/introduction-to-ql.rst @@ -1,22 +1,21 @@ Introduction to QL ================== -QL is the powerful query language that underlies CodeQL, which is used to analyze code. -Queries written with CodeQL can find errors and uncover variants of important security vulnerabilities. -Visit `GitHub Security Lab `__ to read about examples of vulnerabilities that we have recently found in open source projects. - -Before diving into code analysis with CodeQL, it can be helpful to learn about the underlying language more generally. - -QL is a logic programming language, so it is built up of logical formulas. QL uses common logical connectives (such as ``and``, ``or``, and ``not``), quantifiers (such as ``forall`` and ``exists``), and other important logical concepts such as predicates. - -QL also supports recursion and aggregates. This allows you to write complex recursive queries using simple QL syntax and directly use aggregates such as ``count``, ``sum``, and ``average``. +Work through some simple exercises and examples to learn about the basics of QL and CodeQL. Basic syntax ------------ The basic syntax of QL will look familiar to anyone who has used SQL, but it is used somewhat differently. -A query is defined by a **select** clause, which specifies what the result of the query should be. You can try out the examples and exercises in this topic directly in LGTM. Open the `query console `__. Before you can run a query, you need to select a language and project to query (for these logic examples, any language and project will do). +QL is a logic programming language, so it is built up of logical formulas. QL uses common logical connectives (such as ``and``, ``or``, and ``not``), quantifiers (such as ``forall`` and ``exists``), and other important logical concepts such as predicates. + +QL also supports recursion and aggregates. This allows you to write complex recursive queries using simple QL syntax and directly use aggregates such as ``count``, ``sum``, and ``average``. + +Running a query +--------------- + +You can try out the following examples and exercises using `CodeQL for VS Code `__, or you can run them in the `query console on LGTM.com `__. Before you can run a query on LGTM.com, you need to select a language and project to query (for these logic examples, any language and project will do). Once you have selected a language, the query console is populated with the query: @@ -26,7 +25,7 @@ Once you have selected a language, the query console is populated with the query select "hello world" -This query simply returns the string ``"hello world"``. +This query returns the string ``"hello world"``. More complicated queries typically look like this: @@ -49,14 +48,14 @@ Note that ``int`` specifies that the **type** of ``x`` and ``y`` is 'integer'. T Simple exercises ---------------- -You can try to write simple queries using the some of the basic functions that are available for the ``integer``, ``date``, ``float``, ``boolean`` and ``string`` types. To apply a function, simply append it to the argument. For example, ``1.toString()`` converts the value ``1`` to a string. Notice that as you start typing a function, a pop-up is displayed making it easy to select the function that you want. Also note that you can apply multiple functions in succession. For example, ``100.log().sqrt()`` first takes the natural logarithm of 100 and then computes the square root of the result. +You can write simple queries using the some of the basic functions that are available for the ``int``, ``date``, ``float``, ``boolean`` and ``string`` types. To apply a function, append it to the argument. For example, ``1.toString()`` converts the value ``1`` to a string. Notice that as you start typing a function, a pop-up is displayed making it easy to select the function that you want. Also note that you can apply multiple functions in succession. For example, ``100.log().sqrt()`` first takes the natural logarithm of 100 and then computes the square root of the result. Exercise 1 ~~~~~~~~~~ Write a query which returns the length of the string ``"lgtm"``. (Hint: `here `__ is the list of the functions that can be applied to strings.) -➤ `Answer `__ +➤ `See answer in the query console on LGTM.com `__ There is often more than one way to define a query. For example, we can also write the above query in the shorter form: @@ -69,24 +68,24 @@ Exercise 2 Write a query which returns the sine of the minimum of ``3^5`` (``3`` raised to the power ``5``) and ``245.6``. -➤ `Answer `__ +➤ `See answer in the query console on LGTM.com `__ Exercise 3 ~~~~~~~~~~ Write a query which returns the opposite of the boolean ``false``. -➤ `Answer `__ +➤ `See answer in the query console on LGTM.com `__ Exercise 4 ~~~~~~~~~~ Write a query which computes the number of days between June 10 and September 28, 2017. -➤ `Answer `__ +➤ `See answer in the query console on LGTM.com `__ -Example queries ---------------- +Example query with multiple results +----------------------------------- The exercises above all show queries with exactly one result, but in fact many queries have multiple results. For example, the following query computes all `Pythagorean triples `__ between 1 and 10: @@ -97,7 +96,7 @@ The exercises above all show queries with exactly one result, but in fact many q x*x + y*y = z*z select x, y, z -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ To simplify the query, we can introduce a class ``SmallInt`` representing the integers between 1 and 10. We can also define a predicate ``square()`` on integers in that class. Defining classes and predicates in this way makes it easy to reuse code without having to repeat it every time. @@ -112,17 +111,18 @@ To simplify the query, we can introduce a class ``SmallInt`` representing the in where x.square() + y.square() = z.square() select x, y, z -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ -Now that you've seen some general examples, let's use the CodeQL libraries to analyze projects. -In particular, LGTM generates a database representing the code and then CodeQL is used to query this database. See `Database generation `__ for more details on how the database is built. +Example CodeQL queries +---------------------- -.. XX: Perhaps a link to the "CodeQL libraries for X"? +The previous examples used the primitive types built in to QL. Although we chose a project to query, we didn't use the information in that project's database. +The following example queries *do* use these databases and give you an idea of how to use CodeQL to analyze projects. -The previous exercises just used the primitive types built in to QL. Although we chose a project to query, they did not use the project-specific database. The following example queries *do* use these databases and give you an idea of what CodeQL can be used for. There are more details about how to use CodeQL `below <#learning-ql>`__, so don't worry if you don't fully understand these examples yet! +Queries using the CodeQL libraries can find errors and uncover variants of important security vulnerabilities in codebases. +Visit `GitHub Security Lab `__ to read about examples of vulnerabilities that we have recently found in open source projects. -Python -~~~~~~ +To import the CodeQL library for a specific programming language, type ``import `` at the start of the query. .. code-block:: ql @@ -132,10 +132,7 @@ Python where count(f.getAnArg()) > 7 select f -➤ `See this in the query console `__. The ``from`` clause defines a variable ``f`` representing a function. The ``where`` part limits the functions ``f`` to those with more than 7 arguments. Finally, the ``select`` clause lists these functions. - -JavaScript -~~~~~~~~~~ +➤ `See this in the query console on LGTM.com `__. The ``from`` clause defines a variable ``f`` representing a Python function. The ``where`` part limits the functions ``f`` to those with more than 7 arguments. Finally, the ``select`` clause lists these functions. .. code-block:: ql @@ -145,10 +142,7 @@ JavaScript where c.getText().regexpMatch("(?si).*\\bTODO\\b.*") select c -➤ `See this in the query console `__. The ``from`` clause defines a variable ``c`` representing a comment. The ``where`` part limits the comments ``c`` to those containing the word ``"TODO"``. The ``select`` clause lists these comments. - -Java -~~~~ +➤ `See this in the query console on LGTM.com `__. The ``from`` clause defines a variable ``c`` representing a JavaScript comment. The ``where`` part limits the comments ``c`` to those containing the word ``"TODO"``. The ``select`` clause lists these comments. .. code-block:: ql @@ -158,11 +152,11 @@ Java where not exists(p.getAnAccess()) select p -➤ `See this in the query console `__. The ``from`` clause defines a variable ``p`` representing a parameter. The ``where`` clause finds unused parameters by limiting the parameters ``p`` to those which are not accessed. Finally, the ``select`` clause lists these parameters. +➤ `See this in the query console on LGTM.com `__. The ``from`` clause defines a variable ``p`` representing a Java parameter. The ``where`` clause finds unused parameters by limiting the parameters ``p`` to those which are not accessed. Finally, the ``select`` clause lists these parameters. -Learning CodeQL +Further reading --------------- -- To find out more about how to write your own queries, try working through the :doc:`QL detective tutorials `. +- To find out more about how to write your own queries, try working through the :doc:`QL tutorials `. - For an overview of the other available resources, see :doc:`Learning CodeQL <../index>`. -- For a more technical description of the underlying language, see :doc:`About QL `. +- For a more technical description of the underlying language, see the `QL language reference `__. \ No newline at end of file diff --git a/docs/language/learn-ql/java/annotations.rst b/docs/language/learn-ql/java/annotations.rst index 9fbb70776c4..497f20e1ff3 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -1,19 +1,19 @@ -Tutorial: Annotations -===================== - -Overview --------- +Annotations in Java +=================== CodeQL databases of Java projects contain information about all annotations attached to program elements. -Annotations are represented by the following CodeQL classes: +About working with annotations +------------------------------ + +Annotations are represented by these CodeQL classes: - The class ``Annotatable`` represents all entities that may have an annotation attached to them (that is, packages, reference types, fields, methods, and local variables). - The class ``AnnotationType`` represents a Java annotation type, such as ``java.lang.Override``; annotation types are interfaces. - The class ``AnnotationElement`` represents an annotation element, that is, a member of an annotation type. - The class ``Annotation`` represents an annotation such as ``@Override``; annotation values can be accessed through member predicate ``getValue``. -As an example, recall that the Java standard library defines an annotation ``SuppressWarnings`` that instructs the compiler not to emit certain kinds of warnings. It is defined as follows: +For example, the Java standard library defines an annotation ``SuppressWarnings`` that instructs the compiler not to emit certain kinds of warnings: .. code-block:: java @@ -25,7 +25,7 @@ As an example, recall that the Java standard library defines an annotation ``Sup ``SuppressWarnings`` is represented as an ``AnnotationType``, with ``value`` as its only ``AnnotationElement``. -A typical usage of ``SuppressWarnings`` would be the following annotation to prevent a warning about using raw types: +A typical usage of ``SuppressWarnings`` would be this annotation for preventing a warning about using raw types: .. code-block:: java @@ -37,7 +37,7 @@ A typical usage of ``SuppressWarnings`` would be the following annotation to pre The expression ``@SuppressWarnings("rawtypes")`` is represented as an ``Annotation``. The string literal ``"rawtypes"`` is used to initialize the annotation element ``value``, and its value can be extracted from the annotation by means of the ``getValue`` predicate. -We could then write the following query to find all ``@SuppressWarnings`` annotations attached to constructors, and return both the annotation itself and the value of its ``value`` element: +We could then write this query to find all ``@SuppressWarnings`` annotations attached to constructors, and return both the annotation itself and the value of its ``value`` element: .. code-block:: ql @@ -49,7 +49,7 @@ We could then write the following query to find all ``@SuppressWarnings`` annota anntp.hasQualifiedName("java.lang", "SuppressWarnings") select ann, ann.getValue("value") -➤ `See the full query in the query console `__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. +➤ `See the full query in the query console on LGTM.com `__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. As another example, this query finds all annotation types that only have a single annotation element, which has name ``value``: @@ -64,14 +64,14 @@ As another example, this query finds all annotation types that only have a singl ) select anntp -➤ `See the full query in the query console `__. +➤ `See the full query in the query console on LGTM.com `__. Example: Finding missing ``@Override`` annotations -------------------------------------------------- -In newer versions of Java, it is recommended (though not required) to annotate methods that override another method with an ``@Override`` annotation. These annotations, which are checked by the compiler, serve as documentation, and also help you avoid accidental overloading where overriding was intended. +In newer versions of Java, it's recommended (though not required) that you annotate methods that override another method with an ``@Override`` annotation. These annotations, which are checked by the compiler, serve as documentation, and also help you avoid accidental overloading where overriding was intended. -For example, consider the following example program: +For example, consider this example program: .. code-block:: java @@ -89,9 +89,9 @@ For example, consider the following example program: Here, both ``Sub1.m`` and ``Sub2.m`` override ``Super.m``, but only ``Sub1.m`` is annotated with ``@Override``. -We will now develop a query for finding methods like ``Sub2.m`` that should be annotated with ``@Override``, but are not. +We'll now develop a query for finding methods like ``Sub2.m`` that should be annotated with ``@Override``, but are not. -As a first step, let us write a query that finds all ``@Override`` annotations. Annotations are expressions, so their type can be accessed using ``getType``. Annotation types, on the other hand, are interfaces, so their qualified name can be queried using ``hasQualifiedName``. Therefore we can implement the query as follows: +As a first step, let's write a query that finds all ``@Override`` annotations. Annotations are expressions, so their type can be accessed using ``getType``. Annotation types, on the other hand, are interfaces, so their qualified name can be queried using ``hasQualifiedName``. Therefore we can implement the query like this: .. code-block:: ql @@ -111,7 +111,7 @@ As always, it is a good idea to try this query on a CodeQL database for a Java p } } -This makes it very easy to write our query for finding methods that override another method, but do not have an ``@Override`` annotation: we use predicate ``overrides`` to find out whether one method overrides another, and predicate ``getAnAnnotation`` (available on any ``Annotatable``) to retrieve some annotation. +This makes it very easy to write our query for finding methods that override another method, but don't have an ``@Override`` annotation: we use predicate ``overrides`` to find out whether one method overrides another, and predicate ``getAnAnnotation`` (available on any ``Annotatable``) to retrieve some annotation. .. code-block:: ql @@ -122,14 +122,14 @@ This makes it very easy to write our query for finding methods that override ano not overriding.getAnAnnotation() instanceof OverrideAnnotation select overriding, "Method overrides another method, but does not have an @Override annotation." -➤ `See this in the query console `__. In practice, this query may yield many results from compiled library code, which are not very interesting. Therefore, it is a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. +➤ `See this in the query console on LGTM.com `__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. Example: Finding calls to deprecated methods -------------------------------------------- As another example, we can write a query that finds calls to methods marked with a ``@Deprecated`` annotation. -For example, consider the following example program: +For example, consider this example program: .. code-block:: java @@ -147,7 +147,7 @@ For example, consider the following example program: Here, both ``A.m`` and ``A.n`` are marked as deprecated. Methods ``n`` and ``r`` both call ``m``, but note that ``n`` itself is deprecated, so we probably should not warn about this call. -Like in the previous example, we start by defining a class for representing ``@Deprecated`` annotations: +As in the previous example, we'll start by defining a class for representing ``@Deprecated`` annotations: .. code-block:: ql @@ -167,7 +167,7 @@ Now we can define a class for representing deprecated methods: } } -Finally, we use these classes to find calls to deprecated methods, excluding calls that themselves appear in deprecated methods (see :doc:`Tutorial: Navigating the call graph ` for more information on class ``Call``): +Finally, we use these classes to find calls to deprecated methods, excluding calls that themselves appear in deprecated methods: .. code-block:: ql @@ -178,7 +178,9 @@ Finally, we use these classes to find calls to deprecated methods, excluding cal and not call.getCaller() instanceof DeprecatedMethod select call, "This call invokes a deprecated method." -On our example, this query flags the call to ``A.m`` in ``A.r``, but not the one in ``A.n``. +In our example, this query flags the call to ``A.m`` in ``A.r``, but not the one in ``A.n``. + +For more information about the class ``Call``, see :doc:`Navigating the call graph `. Improvements ~~~~~~~~~~~~ @@ -233,11 +235,11 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress and not call.getCaller().getAnAnnotation() instanceof SuppressDeprecationWarningAnnotation select call, "This call invokes a deprecated method." -➤ `See this in the query console `__. It's fairly common for projects to contain calls to methods that appear to be deprecated. +➤ `See this in the query console on LGTM.com `__. It's fairly common for projects to contain calls to methods that appear to be deprecated. -What next? ----------- +Further reading +--------------- -- Take a look at some of the other tutorials: :doc:`Tutorial: Javadoc ` and :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index 268b95acac5..f34e2eec764 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -1,5 +1,7 @@ -AST class reference -=================== +Classes for working with Java code +================================== + +CodeQL has a large selection of classes for working with Java statements and expressions. .. _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 diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index cfaa33cad9f..6f7874c772f 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -1,8 +1,10 @@ -Tutorial: Navigating the call graph -=================================== +Navigating the call graph +========================= -Call graph API --------------- +CodeQL has classes for identifying code that calls other code, and code that can be called from elsewhere. This allows you to find, for example, methods that are never used. + +Call graph classes +------------------ The CodeQL library for Java provides two abstract classes for representing a program's call graph: ``Callable`` and ``Call``. The former is simply the common superclass of ``Method`` and ``Constructor``, the latter is a common superclass of ``MethodAccess``, ``ClassInstanceExpression``, ``ThisConstructorInvocationStmt`` and ``SuperConstructorInvocationStmt``. Simply put, a ``Callable`` is something that can be invoked, and a ``Call`` is something that invokes a ``Callable``. @@ -56,7 +58,7 @@ Class ``Call`` provides two call graph navigation predicates: For instance, in our example ``getCallee`` of the second call in ``Client.main`` would return ``Super.getX``. At runtime, though, this call would actually invoke ``Sub.getX``. -Class ``Callable`` defines a large number of member predicates; for our purposes, the two most important ones are as follows: +Class ``Callable`` defines a large number of member predicates; for our purposes, the two most important ones are: - ``calls(Callable target)`` succeeds if this callable contains a call whose callee is ``target``. - ``polyCalls(Callable target)`` succeeds if this callable may call ``target`` at runtime; this is the case if it contains a call whose callee is either ``target`` or a method that ``target`` overrides. @@ -66,7 +68,7 @@ In our example, ``Client.main`` calls the constructor ``Sub(int)`` and the metho Example: Finding unused methods ------------------------------- -Given this API, we can easily write a query that finds methods that are not called by any other method: +We can use the ``Callable`` class to write a query that finds methods that are not called by any other method: .. code-block:: ql @@ -76,7 +78,7 @@ Given this API, we can easily write a query that finds methods that are not call where not exists(Callable caller | caller.polyCalls(callee)) select callee -➤ `See this in the query console `__. This simple query typically returns a large number of results. +➤ `See this in the query console on LGTM.com `__. This simple query typically returns a large number of results. .. pull-quote:: @@ -84,7 +86,7 @@ Given this API, we can easily write a query that finds methods that are not call We have to use ``polyCalls`` instead of ``calls`` here: we want to be reasonably sure that ``callee`` is not called, either directly or via overriding. -Running this query on a typical Java project results in lots of hits in the Java standard library. This makes sense, since no single client program uses every method of the standard library. More generally, we may want to exclude methods and constructors from compiled libraries. We can use the predicate ``fromSource`` to check whether a compilation unit is a source file, and refine our query as follows: +Running this query on a typical Java project results in lots of hits in the Java standard library. This makes sense, since no single client program uses every method of the standard library. More generally, we may want to exclude methods and constructors from compiled libraries. We can use the predicate ``fromSource`` to check whether a compilation unit is a source file, and refine our query: .. code-block:: ql @@ -95,7 +97,7 @@ Running this query on a typical Java project results in lots of hits in the Java callee.getCompilationUnit().fromSource() select callee, "Not called." -➤ `See this in the query console `__. This change reduces the number of results returned for most projects. +➤ `See this in the query console on LGTM.com `__. This change reduces the number of results returned for most projects. We might also notice several unused methods with the somewhat strange name ````: these are class initializers; while they are not explicitly called anywhere in the code, they are called implicitly whenever the surrounding class is loaded. Hence it makes sense to exclude them from our query. While we are at it, we can also exclude finalizers, which are similarly invoked implicitly: @@ -109,7 +111,7 @@ We might also notice several unused methods with the somewhat strange name ``") and not callee.hasName("finalize") select callee, "Not called." -➤ `See this in the query console `__. This also reduces the number of results returned by most projects. +➤ `See this in the query console on LGTM.com `__. This also reduces the number of results returned by most projects. We may also want to exclude public methods from our query, since they may be external API entry points: @@ -124,7 +126,7 @@ We may also want to exclude public methods from our query, since they may be ext not callee.isPublic() select callee, "Not called." -➤ `See this in the query console `__. This should have a more noticeable effect on the number of results returned. +➤ `See this in the query console on LGTM.com `__. This should have a more noticeable effect on the number of results returned. A further special case is non-public default constructors: in the singleton pattern, for example, a class is provided with private empty default constructor to prevent it from being instantiated. Since the very purpose of such constructors is their not being called, they should not be flagged up: @@ -140,9 +142,9 @@ A further special case is non-public default constructors: in the singleton patt not callee.(Constructor).getNumberOfParameters() = 0 select callee, "Not called." -➤ `See this in the query console `__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. +➤ `See this in the query console on LGTM.com `__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. -Finally, on many Java projects there are methods that are invoked indirectly by reflection. Thus, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The QL Java library has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: +Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The QL Java library has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: .. code-block:: ql @@ -157,11 +159,11 @@ Finally, on many Java projects there are methods that are invoked indirectly by not callee.getDeclaringType() instanceof TestClass select callee, "Not called." -➤ `See this in the query console `__. This should give a further reduction in the number of results returned. +➤ `See this in the query console on LGTM.com `__. This should give a further reduction in the number of results returned. -What next? ----------- +Further reading +--------------- -- Find out how to query metadata and white space: :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/dataflow.rst b/docs/language/learn-ql/java/dataflow.rst index 98b8b97e153..60107f62195 100644 --- a/docs/language/learn-ql/java/dataflow.rst +++ b/docs/language/learn-ql/java/dataflow.rst @@ -1,13 +1,15 @@ Analyzing data flow in Java -============================ +=========================== -Overview --------- +You can use CodeQL to track the flow of data through a Java program to its use. -This topic describes how data flow analysis is implemented in the CodeQL libraries for Java and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. +About this article +------------------ -For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. +This article describes how data flow analysis is implemented in the CodeQL libraries for Java and includes examples to help you write your own data flow queries. +The following sections describe how to use the libraries for local data flow, global data flow, and taint tracking. + +For a more general introduction to modeling data flow, see :doc:`About data flow analysis <../intro-to-data-flow>`. Local data flow --------------- @@ -17,7 +19,7 @@ Local data flow is data flow within a single method or callable. Local data flow Using local data flow ~~~~~~~~~~~~~~~~~~~~~ -The local data flow library is in the module ``DataFlow``, which defines the class ``Node`` denoting any element that data can flow through. ``Node``\ s are divided into expression nodes (``ExprNode``) and parameter nodes (``ParameterNode``). It is possible to map between data flow nodes and expressions/parameters using the member predicates ``asExpr`` and ``asParameter``: +The local data flow library is in the module ``DataFlow``, which defines the class ``Node`` denoting any element that data can flow through. ``Node``\ s are divided into expression nodes (``ExprNode``) and parameter nodes (``ParameterNode``). You can map between data flow nodes and expressions/parameters using the member predicates ``asExpr`` and ``asParameter``: .. code-block:: ql @@ -45,9 +47,9 @@ or using the predicates ``exprNode`` and ``parameterNode``: */ ParameterNode parameterNode(Parameter p) { ... } -The predicate ``localFlowStep(Node nodeFrom, Node nodeTo)`` holds if there is an immediate data flow edge from the node ``nodeFrom`` to the node ``nodeTo``. The predicate can be applied recursively (using the ``+`` and ``*`` operators), or through the predefined recursive predicate ``localFlow``, which is equivalent to ``localFlowStep*``. +The predicate ``localFlowStep(Node nodeFrom, Node nodeTo)`` holds if there is an immediate data flow edge from the node ``nodeFrom`` to the node ``nodeTo``. You can apply the predicate recursively by using the ``+`` and ``*`` operators, or by using the predefined recursive predicate ``localFlow``, which is equivalent to ``localFlowStep*``. -For example, finding flow from a parameter ``source`` to an expression ``sink`` in zero or more local steps can be achieved as follows: +For example, you can find flow from a parameter ``source`` to an expression ``sink`` in zero or more local steps: .. code-block:: ql @@ -65,9 +67,9 @@ Local taint tracking extends local data flow by including non-value-preserving f If ``x`` is a tainted string then ``y`` is also tainted. -The local taint tracking library is in the module ``TaintTracking``. Like local data flow, a predicate ``localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)`` holds if there is an immediate taint propagation edge from the node ``nodeFrom`` to the node ``nodeTo``. The predicate can be applied recursively (using the ``+`` and ``*`` operators), or through the predefined recursive predicate ``localTaint``, which is equivalent to ``localTaintStep*``. +The local taint tracking library is in the module ``TaintTracking``. Like local data flow, a predicate ``localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo)`` holds if there is an immediate taint propagation edge from the node ``nodeFrom`` to the node ``nodeTo``. You can apply the predicate recursively by using the ``+`` and ``*`` operators, or by using the predefined recursive predicate ``localTaint``, which is equivalent to ``localTaintStep*``. -For example, finding taint propagation from a parameter ``source`` to an expression ``sink`` in zero or more local steps can be achieved as follows: +For example, you can find taint propagation from a parameter ``source`` to an expression ``sink`` in zero or more local steps: .. code-block:: ql @@ -76,7 +78,7 @@ For example, finding taint propagation from a parameter ``source`` to an express Examples ~~~~~~~~ -The following query finds the filename passed to ``new FileReader(..)``. +This query finds the filename passed to ``new FileReader(..)``. .. code-block:: ql @@ -88,7 +90,7 @@ The following query finds the filename passed to ``new FileReader(..)``. call.getCallee() = fileReader select call.getArgument(0) -Unfortunately, this will only give the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument: +Unfortunately, this only gives the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument: .. code-block:: ql @@ -102,7 +104,7 @@ Unfortunately, this will only give the expression in the argument, not the value DataFlow::localFlow(DataFlow::exprNode(src), DataFlow::exprNode(call.getArgument(0))) select src -Then we can make the source more specific, for example an access to a public parameter. The following query finds where a public parameter is passed to ``new FileReader(..)``: +Then we can make the source more specific, for example an access to a public parameter. This query finds where a public parameter is passed to ``new FileReader(..)``: .. code-block:: ql @@ -116,7 +118,7 @@ Then we can make the source more specific, for example an access to a public par DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(call.getArgument(0))) select p -The following example finds calls to formatting functions where the format string is not hard-coded. +This query finds calls to formatting functions where the format string is not hard-coded. .. code-block:: ql @@ -145,10 +147,14 @@ 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 ~~~~~~~~~~~~~~~~~~~~~~ -The global data flow library is used by extending the class ``DataFlow::Configuration`` as follows: +You use the global data flow library by extending the class ``DataFlow::Configuration``: .. code-block:: ql @@ -166,7 +172,7 @@ The global data flow library is used by extending the class ``DataFlow::Configur } } -The following predicates are defined in the configuration: +These predicates are defined in the configuration: - ``isSource``—defines where data may flow from - ``isSink``—defines where data may flow to @@ -186,7 +192,7 @@ The data flow analysis is performed using the predicate ``hasFlow(DataFlow::Node Using global taint tracking ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Global taint tracking is to global data flow as local taint tracking is to local data flow. That is, global taint tracking extends global data flow with additional non-value-preserving steps. The global taint tracking library is used by extending the class ``TaintTracking::Configuration`` as follows: +Global taint tracking is to global data flow as local taint tracking is to local data flow. That is, global taint tracking extends global data flow with additional non-value-preserving steps. You use the global taint tracking library by extending the class ``TaintTracking::Configuration``: .. code-block:: ql @@ -204,7 +210,7 @@ Global taint tracking is to global data flow as local taint tracking is to local } } -The following predicates are defined in the configuration: +These predicates are defined in the configuration: - ``isSource``—defines where taint may flow from - ``isSink``—defines where taint may flow to @@ -223,7 +229,7 @@ The data flow library contains some predefined flow sources. The class ``RemoteF Examples ~~~~~~~~ -The following example shows a taint-tracking configuration that uses remote user input as data sources. +This query shows a taint-tracking configuration that uses remote user input as data sources. .. code-block:: ql @@ -251,12 +257,12 @@ 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>`__) -What next? ----------- +Further reading +--------------- -- Try the worked examples in the following topics: :doc:`Tutorial: Navigating the call graph ` and :doc:`Tutorial: Working with source locations `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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 ------- diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index 25d605b18b8..24fb943ace5 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -1,12 +1,14 @@ -Tutorial: Expressions and statements -==================================== +Overflow-prone comparisons in Java +================================== -Overview --------- +You can use CodeQL to check for comparisons in Java code where one side of the comparison is prone to overflow. -This tutorial develops a query for finding comparisons between integers and long integers in loops that may lead to non-termination due to overflow. +About this article +------------------ -Specifically, consider the following code snippet: +In this tutorial article you'll write a query for finding comparisons between integers and long integers in loops that may lead to non-termination due to overflow. + +To begin, consider this code snippet: .. code-block:: java @@ -24,12 +26,12 @@ 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 will develop a query that finds code that looks like it might exhibit this kind of behavior. We will be using several of the standard library classes for representing statements and functions, a full list of which can be found in the :doc:`AST class reference `. +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 `. Initial query ------------- -We start out by writing a query that finds less-than expressions (CodeQL class ``LTExpr``) where the left operand is of type ``int`` and the right operand is of type ``long``: +We'll start by writing a query that finds less-than expressions (CodeQL class ``LTExpr``) where the left operand is of type ``int`` and the right operand is of type ``long``: .. code-block:: ql @@ -40,9 +42,9 @@ We start out by writing a query that finds less-than expressions (CodeQL class ` expr.getRightOperand().getType().hasName("long") select expr -➤ `See this in the query console `__. This query usually finds results on most projects. +➤ `See this in the query console on LGTM.com `__. This query usually finds results on most projects. -Notice that we use the predicate ``getType`` (available on all subclasses of ``Expr``) to determine the type of the operands. Types, in turn, define the ``hasName`` predicate, which allows us to identify the primitive types ``int`` and ``long``. As it stands, this query finds *all* less-than expressions comparing ``int`` and ``long``, but in fact we are only interested in comparisons that are part of a loop condition. Also, we want to filter out comparisons where either operand is constant, since these are less likely to be real bugs. The revised query looks as follows: +Notice that we use the predicate ``getType`` (available on all subclasses of ``Expr``) to determine the type of the operands. Types, in turn, define the ``hasName`` predicate, which allows us to identify the primitive types ``int`` and ``long``. As it stands, this query finds *all* less-than expressions comparing ``int`` and ``long``, but in fact we are only interested in comparisons that are part of a loop condition. Also, we want to filter out comparisons where either operand is constant, since these are less likely to be real bugs. The revised query looks like this: .. code-block:: ql @@ -55,7 +57,7 @@ Notice that we use the predicate ``getType`` (available on all subclasses of ``E not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See this in the query console `__. Notice that fewer results are found. +➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found. The class ``LoopStmt`` is a common superclass of all loops, including, in particular, ``for`` loops as in our example above. While different kinds of loops have different syntax, they all have a loop condition, which can be accessed through predicate ``getCondition``. We use the reflexive transitive closure operator ``*`` applied to the ``getAChildExpr`` predicate to express the requirement that ``expr`` should be nested inside the loop condition. In particular, it can be the loop condition itself. @@ -78,7 +80,7 @@ In order to compare the ranges of types, we define a predicate that returns the (pt.hasName("long") and result=64) } -We now want to generalize our query to apply to any comparison where the width of the type on the smaller end of the comparison is less than the width of the type on the greater end. Let us call such a comparison *overflow prone*, and introduce an abstract class to model it: +We now want to generalize our query to apply to any comparison where the width of the type on the smaller end of the comparison is less than the width of the type on the greater end. Let's call such a comparison *overflow prone*, and introduce an abstract class to model it: .. code-block:: ql @@ -118,11 +120,11 @@ Now we rewrite our query to make use of these new classes: not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See the full query in the query console `__. +➤ `See the full query in the query console on LGTM.com `__. -What next? ----------- +Further reading +--------------- -- Have a look at some of the other tutorials: :doc:`Tutorial: Types and the class hierarchy `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index cf8a2f3c27c..8fd21c2d0c2 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -1,8 +1,10 @@ -Introducing the CodeQL libraries for Java -========================================= +CodeQL library for Java +======================= -Overview --------- +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. + +About the CodeQL library for Java +--------------------------------- There is an extensive library for analyzing CodeQL databases extracted from Java projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. @@ -12,13 +14,13 @@ The library is implemented as a set of QL modules, that is, files with the exten import java -The rest of this topic briefly summarizes the most important classes and predicates provided by this library. +The rest of this article briefly summarizes the most important classes and predicates provided by this library. .. pull-quote:: Note - The example queries in this topic illustrate the types of results returned by different library classes. The results themselves are not interesting but can be used as the basis for developing a more complex query. The tutorial topics show how you can take a simple query and fine-tune it to find precisely the results you're interested in. + The example queries in this article illustrate the types of results returned by different library classes. The results themselves are not interesting but can be used as the basis for developing a more complex query. The other articles in this section of the help show how you can take a simple query and fine-tune it to find precisely the results you're interested in. Summary of the library classes ------------------------------ @@ -40,7 +42,7 @@ These classes represent named program elements: packages (``Package``), compilat Their common superclass is ``Element``, which provides general member predicates for determining the name of a program element and checking whether two elements are nested inside each other. -It is often convenient to refer to an element that might either be a method or a constructor; the class ``Callable``, which is a common superclass of ``Method`` and ``Constructor``, can be used for this purpose. +It's often convenient to refer to an element that might either be a method or a constructor; the class ``Callable``, which is a common superclass of ``Method`` and ``Constructor``, can be used for this purpose. Types ~~~~~ @@ -66,9 +68,9 @@ For example, the following query finds all variables of type ``int`` in the prog pt.hasName("int") select v -➤ `See this in the query console `__. You are likely to get many results when you run this query because most projects contain many variables of type ``int``. +➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``. -Reference types can also be categorized according to their declaration scope: +Reference types are also categorized according to their declaration scope: - ``TopLevelType`` represents a reference type declared at the top-level of a compilation unit. - ``NestedType`` is a type declared inside another type. @@ -83,7 +85,7 @@ For instance, this query finds all top-level types whose name is not the same as where tl.getName() != tl.getCompilationUnit().getName() select tl -➤ `See this in the query console `__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. +➤ `See this in the query console on LGTM.com `__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. Several more specialized classes are available as well: @@ -105,7 +107,7 @@ As an example, we can write a query that finds all nested classes that directly where nc.getASupertype() instanceof TypeObject select nc -➤ `See this in the query console `__. You are likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. +➤ `See this in the query console on LGTM.com `__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. Generics ~~~~~~~~ @@ -139,7 +141,7 @@ For instance, we could use the following query to find all parameterized instanc pt.getSourceDeclaration() = map select pt -➤ `See this in the query console `__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. In general, generic types may restrict which types a type parameter can be bound to. For instance, a type of maps from strings to numbers could be declared as follows: @@ -162,7 +164,7 @@ As an example, the following query finds all type variables with type bound ``Nu tb.getType().hasQualifiedName("java.lang", "Number") select tv -➤ `See this in the query console `__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *gradle/gradle* and *hibernate/hibernate-orm* projects all contained examples of this pattern. +➤ `See this in the query console on LGTM.com `__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *gradle/gradle* and *hibernate/hibernate-orm* projects all contained examples of this pattern. For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In the CodeQL libraries, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``: @@ -175,7 +177,7 @@ For dealing with legacy code that is unaware of generics, every generic type has rt.getSourceDeclaration().hasQualifiedName("java.util", "Map") select v -➤ `See this in the query console `__. Many projects have variables of raw type ``Map``. +➤ `See this in the query console on LGTM.com `__. Many projects have variables of raw type ``Map``. For example, in the following code snippet this query would find ``m1``, but not ``m2``: @@ -194,7 +196,7 @@ The wildcards ``? extends Number`` and ``? super Float`` are represented by clas For dealing with generic methods, there are classes ``GenericMethod``, ``ParameterizedMethod`` and ``RawMethod``, which are entirely analogous to the like-named classes for representing generic types. -More information on working with types can be found in the :doc:`tutorial on types and the class hierarchy `. +For more information on working with types, see the :doc:`article on Java types `. Variables ~~~~~~~~~ @@ -208,7 +210,7 @@ Class ``Variable`` represents a variable `in the Java sense ` for an exhaustive list of all expression and statement types available in the standard QL library. +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:`Classes for working with Java code `. Both ``Expr`` and ``Stmt`` provide member predicates for exploring the abstract syntax tree of a program: @@ -226,7 +228,7 @@ For example, the following query finds all expressions whose parents are ``retur where e.getParent() instanceof ReturnStmt select e -➤ `See this in the query console `__. Many projects have examples of ``return`` statements with child statements. +➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``return`` statements with child statements. Therefore, if the program contains a return statement ``return x + y;``, this query will return ``x + y``. @@ -240,7 +242,7 @@ As another example, the following query finds statements whose parent is an ``if where s.getParent() instanceof IfStmt select s -➤ `See this in the query console `__. Many projects have examples of ``if`` statements with child statements. +➤ `See this in the query console on LGTM.com `__. Many projects have examples of ``if`` statements with child statements. This query will find both ``then`` branches and ``else`` branches of all ``if`` statements in the program. @@ -254,11 +256,11 @@ Finally, here is a query that finds method bodies: where s.getParent() instanceof Method select s -➤ `See this in the query console `__. Most projects have many method bodies. +➤ `See this in the query console on LGTM.com `__. Most projects have many method bodies. As these examples show, the parent node of an expression is not always an expression: it may also be a statement, for example, an ``IfStmt``. Similarly, the parent node of a statement is not always a statement: it may also be a method or a constructor. To capture this, the QL Java library provides two abstract class ``ExprParent`` and ``StmtParent``, the former representing any node that may be the parent node of an expression, and the latter any node that may be the parent node of a statement. - For more information on working with AST classes, see the :doc:`tutorial on expressions and statements `. +For more information on working with AST classes, see the :doc:`article on overflow-prone comparisons in Java `. Metadata -------- @@ -274,7 +276,7 @@ For annotations, class ``Annotatable`` is a superclass of all program elements t from Constructor c select c.getAnAnnotation() -➤ `See this in the query console `__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. These annotations are represented by class ``Annotation``. An annotation is simply an expression whose type is an ``AnnotationType``. For example, you can amend this query so that it only reports deprecated constructors: @@ -288,9 +290,9 @@ These annotations are represented by class ``Annotation``. An annotation is simp anntp.hasQualifiedName("java.lang", "Deprecated") select ann -➤ `See this in the query console `__. Only constructors with the ``@deprecated`` annotation are reported this time. +➤ `See this in the query console on LGTM.com `__. Only constructors with the ``@deprecated`` annotation are reported this time. -For more information on working with annotations, see the :doc:`tutorial on annotations `. +For more information on working with annotations, see the :doc:`article on annotations `. For Javadoc, class ``Element`` has a member predicate ``getDoc`` that returns a delegate ``Documentable`` object, which can then be queried for its attached Javadoc comments. For example, the following query finds Javadoc comments on private fields: @@ -303,7 +305,7 @@ For Javadoc, class ``Element`` has a member predicate ``getDoc`` that returns a jdoc = f.getDoc().getJavadoc() select jdoc -➤ `See this in the query console `__. You can see this pattern in many projects. +➤ `See this in the query console on LGTM.com `__. You can see this pattern in many projects. Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocElement`` nodes, which can be traversed using member predicates ``getAChild`` and ``getParent``. For instance, you could edit the query so that it finds all ``@author`` tags in Javadoc comments on private fields: @@ -317,7 +319,7 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle at.getParent+() = jdoc select at -➤ `See this in the query console `__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. .. pull-quote:: @@ -325,7 +327,7 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle On line 5 we used ``getParent+`` to capture tags that are nested at any depth within the Javadoc comment. -For more information on working with Javadoc, see the :doc:`tutorial on Javadoc `. +For more information on working with Javadoc, see the :doc:`article on Javadoc `. Metrics ------- @@ -345,7 +347,7 @@ For example, the following query finds methods with a `cyclomatic complexity 40 select m -➤ `See this in the query console `__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. +➤ `See this in the query console on LGTM.com `__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. Call graph ---------- @@ -365,7 +367,7 @@ We can use predicate ``Call.getCallee`` to find out which method or constructor m.hasName("println") select c -➤ `See this in the query console `__. The LGTM.com demo projects all include many calls to methods of this name. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all include many calls to methods of this name. Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So we can find methods and constructors that are never called using this query: @@ -377,13 +379,13 @@ Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So where not exists(c.getAReference()) select c -➤ `See this in the query console `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph `. +➤ `See this in the query console on LGTM.com `__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph `. -For more information about callables and calls, see the :doc:`call graph tutorial `. +For more information about callables and calls, see the :doc:`article on the call graph `. -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the CodeQL for Java tutorial topics: :doc:`Types and the class hierarchy `, :doc:`Expressions and statements `, :doc:`Navigating the call graph `, :doc:`Annotations `, :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:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/javadoc.rst b/docs/language/learn-ql/java/javadoc.rst index bd0a11b9132..85981b4bd59 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -1,8 +1,10 @@ -Tutorial: Javadoc -================= +Javadoc +======= -Overview --------- +You can use CodeQL to find errors in Javadoc comments in Java code. + +About analyzing Javadoc +----------------------- To access Javadoc associated with a program element, we use member predicate ``getDoc`` of class ``Element``, which returns a ``Documentable``. Class ``Documentable``, in turn, offers a member predicate ``getJavadoc`` to retrieve the Javadoc attached to the element in question, if any. @@ -49,9 +51,9 @@ The ``JavadocTag`` has several subclasses representing specific kinds of Javadoc Example: Finding spurious @param tags ------------------------------------- -As an example of using the CodeQL Javadoc API, let us write a query that finds ``@param`` tags that refer to a non-existent parameter. +As an example of using the CodeQL Javadoc API, let's write a query that finds ``@param`` tags that refer to a non-existent parameter. -For example, consider the following program: +For example, consider this program: .. code-block:: java @@ -76,7 +78,7 @@ To begin with, we write a query that finds all callables (that is, methods or co where c.getDoc().getJavadoc() = pt.getParent() select c, pt -It is now easy to add another conjunct to the ``where`` clause, restricting the query to ``@param`` tags that refer to a non-existent parameter: we simply need to require that no parameter of ``c`` has the name ``pt.getParamName()``. +It's now easy to add another conjunct to the ``where`` clause, restricting the query to ``@param`` tags that refer to a non-existent parameter: we simply need to require that no parameter of ``c`` has the name ``pt.getParamName()``. .. code-block:: ql @@ -92,7 +94,7 @@ Example: Finding spurious @throws tags A related, but somewhat more involved, problem is finding ``@throws`` tags that refer to an exception that the method in question cannot actually throw. -For example, consider the following Java program: +For example, consider this Java program: .. code-block:: java @@ -108,9 +110,9 @@ For example, consider the following Java program: } } -Notice that the Javadoc comment of ``A.foo`` documents two thrown exceptions: ``IOException`` and ``RuntimeException``. The former is clearly spurious: ``A.foo`` does not have a ``throws IOException`` clause, and thus cannot throw this kind of exception. On the other hand, ``RuntimeException`` is an unchecked exception, so it can be thrown even if there is no explicit ``throws`` clause listing it. Therefore, our query should flag the ``@throws`` tag for ``IOException``, but not the one for ``RuntimeException.`` +Notice that the Javadoc comment of ``A.foo`` documents two thrown exceptions: ``IOException`` and ``RuntimeException``. The former is clearly spurious: ``A.foo`` doesn't have a ``throws IOException`` clause, and therefore can't throw this kind of exception. On the other hand, ``RuntimeException`` is an unchecked exception, so it can be thrown even if there is no explicit ``throws`` clause listing it. So our query should flag the ``@throws`` tag for ``IOException``, but not the one for ``RuntimeException.`` -Recall from above that the CodeQL library represents ``@throws`` tags using class ``ThrowsTag``. This class does not provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look as follows: +Remember that the CodeQL library represents ``@throws`` tags using class ``ThrowsTag``. This class doesn't provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look like this: .. code-block:: ql @@ -118,7 +120,7 @@ Recall from above that the CodeQL library represents ``@throws`` tags using clas result.hasName(tt.getExceptionName()) } -Similarly, ``Callable`` does not come with a member predicate for querying all exceptions that the method or constructor may possibly throw. We can, however, implement this ourselves by using ``getAnException`` to find all ``throws`` clauses of the callable, and then use ``getType`` to resolve the corresponding exception types: +Similarly, ``Callable`` doesn't come with a member predicate for querying all exceptions that the method or constructor may possibly throw. We can, however, implement this ourselves by using ``getAnException`` to find all ``throws`` clauses of the callable, and then use ``getType`` to resolve the corresponding exception types: .. code-block:: ql @@ -131,7 +133,7 @@ Note the use of ``getASupertype*`` to find both exceptions declared in a ``throw Now we can write a query for finding all callables ``c`` and ``@throws`` tags ``tt`` such that: - ``tt`` belongs to a Javadoc comment attached to ``c``. -- ``c`` cannot throw the exception documented by ``tt``. +- ``c`` can't throw the exception documented by ``tt``. .. code-block:: ql @@ -145,17 +147,17 @@ Now we can write a query for finding all callables ``c`` and ``@throws`` tags `` not mayThrow(c, exn) select tt, "Spurious @throws tag." -➤ `See this in the query console `__. This finds several results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com `__. This finds several results in the LGTM.com demo projects. Improvements ~~~~~~~~~~~~ Currently, there are two problems with this query: -#. ``getDocumentedException`` is too liberal: it will return *any* reference type with the right name, even if it is in a different package and not actually visible in the current compilation unit. -#. ``mayThrow`` is too restrictive: it does not account for unchecked exceptions, which do not need to be declared. +#. ``getDocumentedException`` is too liberal: it will return *any* reference type with the right name, even if it's in a different package and not actually visible in the current compilation unit. +#. ``mayThrow`` is too restrictive: it doesn't account for unchecked exceptions, which do not need to be declared. -To see why the former is a problem, consider the following program: +To see why the former is a problem, consider this program: .. code-block:: java @@ -166,9 +168,9 @@ To see why the former is a problem, consider the following program: void bar() throws IOException {} } -This program defines its own class ``IOException``, which is unrelated to the class ``java.io.IOException`` in the standard library: they are in different packages. Our ``getDocumentedException`` predicate does not check packages, however, so it will consider the ``@throws`` clause to refer to both ``IOException`` classes, and thus flag the ``@param`` tag as spurious, since ``B.bar`` cannot actually throw ``java.io.IOException``. +This program defines its own class ``IOException``, which is unrelated to the class ``java.io.IOException`` in the standard library: they are in different packages. Our ``getDocumentedException`` predicate doesn't check packages, however, so it will consider the ``@throws`` clause to refer to both ``IOException`` classes, and thus flag the ``@param`` tag as spurious, since ``B.bar`` can't actually throw ``java.io.IOException``. -As an example of the second problem, method ``A.foo`` from our previous example was annotated with a ``@throws RuntimeException`` tag. Our current version of ``mayThrow``, however, would think that ``A.foo`` cannot throw a ``RuntimeException``, and thus flag the tag as spurious. +As an example of the second problem, method ``A.foo`` from our previous example was annotated with a ``@throws RuntimeException`` tag. Our current version of ``mayThrow``, however, would think that ``A.foo`` can't throw a ``RuntimeException``, and thus flag the tag as spurious. We can make ``mayThrow`` less restrictive by introducing a new class to represent unchecked exceptions, which are just the subtypes of ``java.lang.RuntimeException`` and ``java.lang.Error``: @@ -196,7 +198,7 @@ Fixing ``getDocumentedException`` is more complicated, but we can easily cover t #. The ``@throws`` tag refers to a type in the same package. #. The ``@throws`` tag refers to a type that is imported by the current compilation unit. -The first case can be covered by changing ``getDocumentedException`` to use the qualified name of the ``@throws`` tag. To handle the second and the third case, we can introduce a new predicate ``visibleIn`` that checks whether a reference type is visible in a compilation unit, either by virtue of belonging to the same package or by being explicitly imported. We then rewrite ``getDocumentedException`` as follows: +The first case can be covered by changing ``getDocumentedException`` to use the qualified name of the ``@throws`` tag. To handle the second and the third case, we can introduce a new predicate ``visibleIn`` that checks whether a reference type is visible in a compilation unit, either by virtue of belonging to the same package or by being explicitly imported. We then rewrite ``getDocumentedException`` as: .. code-block:: ql @@ -212,13 +214,13 @@ The first case can be covered by changing ``getDocumentedException`` to use the (result.hasName(tt.getExceptionName()) and visibleIn(tt.getFile(), result)) } -➤ `See this in the query console `__. This finds many fewer, more interesting results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com `__. This finds many fewer, more interesting results in the LGTM.com demo projects. -Currently, ``visibleIn`` only considers single-type imports, but it would be possible to extend it with support for other kinds of imports. +Currently, ``visibleIn`` only considers single-type imports, but you could extend it with support for other kinds of imports. -What next? ----------- +Further reading +--------------- -- Find out how you can use the location API to define queries on whitespace: :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/ql-for-java.rst b/docs/language/learn-ql/java/ql-for-java.rst index aa26c5ba6bb..3b5b64dd99b 100644 --- a/docs/language/learn-ql/java/ql-for-java.rst +++ b/docs/language/learn-ql/java/ql-for-java.rst @@ -1,8 +1,9 @@ CodeQL for Java =============== +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from Java codebases. + .. toctree:: - :glob: :hidden: introduce-libraries-java @@ -15,29 +16,28 @@ CodeQL for Java source-locations ast-class-reference -These topics provide an overview of the CodeQL libraries for Java and show examples of how to use them. +- `Basic Java query `__: Learn to write and run a simple CodeQL query using LGTM. -- `Basic Java query `__ describes how to write and run queries using LGTM. +- :doc:`CodeQL library for Java `: When analyzing Java code, you can use the large collection of classes in the CodeQL library for Java. -- :doc:`Introducing the CodeQL libraries for Java ` introduces the standard libraries used to write queries for Java code. +- :doc:`Analyzing data flow in Java `: You can use CodeQL to track the flow of data through a Java program to its use. -- :doc:`Tutorial: Analyzing data flow in Java ` demonstrates how to write queries using the standard data flow and taint tracking libraries for Java. +- :doc:`Java types `: You can use CodeQL to find out information about data types used in Java code. This allows you to write queries to identify specific type-related issues. -- :doc:`Tutorial: Types and the class hierarchy ` introduces the classes for representing a program's class hierarchy by means of examples. +- :doc:`Overflow-prone comparisons in Java `: You can use CodeQL to check for comparisons in Java code where one side of the comparison is prone to overflow. -- :doc:`Tutorial: Expressions and statements ` introduces the classes for representing a program's syntactic structure by means of examples. +- :doc:`Navigating the call graph `: CodeQL has classes for identifying code that calls other code, and code that can be called from elsewhere. This allows you to find, for example, methods that are never used. -- :doc:`Tutorial: Navigating the call graph ` is a worked example of how to write a query that navigates a program's call graph to find unused methods. +- :doc:`Annotations in Java `: CodeQL databases of Java projects contain information about all annotations attached to program elements. -- :doc:`Tutorial: Annotations ` introduces the classes for representing annotations by means of examples. +- :doc:`Javadoc `: You can use CodeQL to find errors in Javadoc comments in Java code. -- :doc:`Tutorial: Javadoc ` introduces the classes for representing Javadoc comments by means of examples. +- :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:`Tutorial: Working with source locations ` is a worked example of how to write a query that uses the location information provided in the database for finding likely bugs. +- :doc:`Classes for working with Java code `: CodeQL has a large selection of classes for working with Java statements and expressions. -- :doc:`AST class reference ` gives an overview of all AST classes in the standard CodeQL library for Java. -Other resources +Further reading --------------- - For examples of how to query common Java elements, see the `Java cookbook `__. diff --git a/docs/language/learn-ql/java/source-locations.rst b/docs/language/learn-ql/java/source-locations.rst index 6e29777fab9..7d3506b3923 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -1,10 +1,12 @@ -Tutorial: Working with source locations -======================================= +Working with source locations +============================= -Overview --------- +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. -Java offers a rich set of operators with complex precedence rules, which are sometimes confusing to developers. For instance, the class ``ByteBufferCache`` in the OpenJDK Java compiler (which is a member class of ``com.sun.tools.javac.util.BaseFileManager``) contains the following code for allocating a buffer: +About source locations +---------------------- + +Java offers a rich set of operators with complex precedence rules, which are sometimes confusing to developers. For instance, the class ``ByteBufferCache`` in the OpenJDK Java compiler (which is a member class of ``com.sun.tools.javac.util.BaseFileManager``) contains this code for allocating a buffer: .. code-block:: java @@ -14,14 +16,14 @@ Presumably, the author meant to allocate a buffer that is 1.5 times the size ind Note that the source layout gives a fairly clear indication of the intended meaning: there is more white space around ``+`` than around ``>>``, suggesting that the latter is meant to bind more tightly. -We will now develop a query that finds this kind of suspicious nesting, where the operator of the inner expression has more white space around it than the operator of the outer expression. This pattern may not necessarily indicate a bug, but at the very least it makes the code hard to read and prone to misinterpretation. +We're going to develop a query that finds this kind of suspicious nesting, where the operator of the inner expression has more white space around it than the operator of the outer expression. This pattern may not necessarily indicate a bug, but at the very least it makes the code hard to read and prone to misinterpretation. -White space is not directly represented in the CodeQL database, but we can deduce its presence from the location information associated with program elements and AST nodes. So we will start by providing an overview of source location management in the standard library for Java. +White space is not directly represented in the CodeQL database, but we can deduce its presence from the location information associated with program elements and AST nodes. So, before we write our query, we need an understanding of source location management in the standard library for Java. Location API ------------ -For every entity that has a representation in Java source code (including, in particular, program elements and AST nodes), the standard CodeQL library provides the following predicates for accessing source location information: +For every entity that has a representation in Java source code (including, in particular, program elements and AST nodes), the standard CodeQL library provides these predicates for accessing source location information: - ``getLocation`` returns a ``Location`` object describing the start and end position of the entity. - ``getFile`` returns a ``File`` object representing the file containing the entity. @@ -29,7 +31,7 @@ For every entity that has a representation in Java source code (including, in pa - ``getNumberOfCommentLines`` returns the number of comment lines. - ``getNumberOfLinesOfCode`` returns the number of non-comment lines. -For example, assume the following Java class is defined in compilation unit ``SayHello.java``: +For example, let's assume this Java class is defined in the compilation unit ``SayHello.java``: .. code-block:: java @@ -44,20 +46,20 @@ For example, assume the following Java class is defined in compilation unit ``Sa } } -Invoking ``getFile`` on the expression statement in the body of ``main`` will return a ``File`` object representing the file ``SayHello.java``. The statement spans four lines in total ``(getTotalNumberOfLines``), of which one is a comment line (``getNumberOfCommentLines``), while three lines contain code (``getNumberOfLinesOfCode``). +Invoking ``getFile`` on the expression statement in the body of ``main`` returns a ``File`` object representing the file ``SayHello.java``. The statement spans four lines in total ``(getTotalNumberOfLines``), of which one is a comment line (``getNumberOfCommentLines``), while three lines contain code (``getNumberOfLinesOfCode``). Class ``Location`` defines member predicates ``getStartLine``, ``getEndLine``, ``getStartColumn`` and ``getEndColumn`` to retrieve the line and column number an entity starts and ends at, respectively. Both lines and columns are counted starting from 1 (not 0), and the end position is inclusive, that is, it is the position of the last character belonging to the source code of the entity. In our example, the expression statement starts at line 5, column 3 (the first two characters on the line are tabs, which each count as one character), and it ends at line 8, column 4. -Class ``File`` defines the following member predicates: +Class ``File`` defines these member predicates: - ``getFullName`` returns the fully qualified name of the file. - ``getRelativePath`` returns the path of the file relative to the base directory of the source code. - ``getExtension`` returns the extension of the file. - ``getShortName`` returns the base name of the file, without its extension. -In our example, assume file ``A.java`` is located in directory ``/home/testuser/code/pkg``, where ``/home/testuser/code`` is the base directory of the program being analyzed. Then, a ``File`` object for ``A.java`` returns the following: +In our example, assume file ``A.java`` is located in directory ``/home/testuser/code/pkg``, where ``/home/testuser/code`` is the base directory of the program being analyzed. Then, a ``File`` object for ``A.java`` returns: - ``getFullName`` is ``/home/testuser/code/pkg/A.java``. - ``getRelativePath`` is ``pkg/A.java``. @@ -67,7 +69,7 @@ In our example, assume file ``A.java`` is located in directory ``/home/testuser/ Determining white space around an operator ------------------------------------------ -Let us start by considering how to write a predicate that computes the total amount of white space surrounding the operator of a given binary expression. If ``rcol`` is the start column of the expression's right operand and ``lcol`` is the end column of its left operand, then ``rcol - (lcol+1)`` gives us the total number of characters in between the two operands (note that we have to use ``lcol+1`` instead of ``lcol`` because end positions are inclusive). +Let's start by considering how to write a predicate that computes the total amount of white space surrounding the operator of a given binary expression. If ``rcol`` is the start column of the expression's right operand and ``lcol`` is the end column of its left operand, then ``rcol - (lcol+1)`` gives us the total number of characters in between the two operands (note that we have to use ``lcol+1`` instead of ``lcol`` because end positions are inclusive). This number includes the length of the operator itself, which we need to subtract out. For this, we can use predicate ``getOp``, which returns the operator string, surrounded by one white space on either side. Overall, the expression for computing the amount of white space around the operator of a binary expression ``expr`` is: @@ -88,12 +90,12 @@ Clearly, however, this only works if the entire expression is on a single line, ) } -Notice that we use an ``exists`` to introduce our temporary variables ``lcol`` and ``rcol``. The predicate could be written without them by just inlining ``lcol`` and ``rcol`` into their use, at some cost in readability. +Notice that we use an ``exists`` to introduce our temporary variables ``lcol`` and ``rcol``. You could write the predicate without them by just inlining ``lcol`` and ``rcol`` into their use, at some cost in readability. Find suspicious nesting ----------------------- -A first version of our query can now be written: +Here's a first version of our query: .. code-block:: ql @@ -108,7 +110,7 @@ A first version of our query can now be written: wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console `__. This query is likely to find results on most projects. +➤ `See this in the query console on LGTM.com `__. This query is likely to find results on most projects. The first conjunct of the ``where`` clause restricts ``inner`` to be an operand of ``outer``, the second conjunct binds ``wsinner`` and ``wsouter``, while the last conjunct selects the suspicious cases. @@ -123,7 +125,7 @@ If we run this initial query, we might notice some false positives arising from i< start + 100 -Note that our predicate ``operatorWS`` computes the **total** amount of white space around the operator, which, in this case, is one for the ``<`` and two for the ``+``. Ideally, we would like to exclude cases where the amount of white space before and after the operator are not the same. Currently, CodeQL databases do not record enough information to figure this out, but as an approximation we could require that the total number of white space characters is even: +Note that our predicate ``operatorWS`` computes the **total** amount of white space around the operator, which, in this case, is one for the ``<`` and two for the ``+``. Ideally, we would like to exclude cases where the amount of white space before and after the operator are not the same. Currently, CodeQL databases don't record enough information to figure this out, but as an approximation we could require that the total number of white space characters is even: .. code-block:: ql @@ -139,7 +141,7 @@ Note that our predicate ``operatorWS`` computes the **total** amount of white sp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console `__. Any results will be refined by our changes to the query. +➤ `See this in the query console on LGTM.com `__. Any results will be refined by our changes to the query. Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive.To exclude these cases, let us define a new class identifying binary expressions with an associative operator: @@ -171,7 +173,7 @@ Now we can extend our query to discard results where the outer and the inner exp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console `__. +➤ `See this in the query console on LGTM.com `__. Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase `__: @@ -181,8 +183,8 @@ Notice that we again use ``getOp``, this time to determine whether two binary ex Whitespace suggests that the programmer meant to toggle ``i`` between zero and one, but in fact the expression is parsed as ``i + (1%2)``, which is the same as ``i + 1``, so ``i`` is simply incremented. -What next? ----------- +Further reading +--------------- -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index a438f111cab..3cdafa8389a 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -1,8 +1,10 @@ -Tutorial: Types and the class hierarchy -======================================= +Java types +========== -Overview --------- +You can use CodeQL to find out information about data types used in Java code. This allows you to write queries to identify specific type-related issues. + +About working with Java types +----------------------------- The standard CodeQL library represents Java types by means of the ``Type`` class and its various subclasses. @@ -30,7 +32,7 @@ To determine ancestor types (including immediate super types, and also *their* s where B.hasName("B") select B.getASupertype+() -➤ `See this in the query console `__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. +➤ `See this in the query console on LGTM.com `__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. .. pull-quote:: @@ -59,7 +61,7 @@ If the expression ``e`` happens to actually evaluate to a ``B[]`` array, on the Object[] o = new String[] { "Hello", "world" }; String[] s = (String[])o; -In this tutorial, we do not try to distinguish these two cases. Our query should simply look for cast expressions ``ce`` that cast from some type ``source`` to another type ``target``, such that: +In this tutorial, we don't try to distinguish these two cases. Our query should simply look for cast expressions ``ce`` that cast from some type ``source`` to another type ``target``, such that: - Both ``source`` and ``target`` are array types. - The element type of ``source`` is a transitive super type of the element type of ``target``. @@ -76,7 +78,7 @@ This recipe is not too difficult to translate into a query: target.getElementType().(RefType).getASupertype+() = source.getElementType() select ce, "Potentially problematic array downcast." -➤ `See this in the query console `__. Many projects return results for this query. +➤ `See this in the query console on LGTM.com `__. Many projects return results for this query. Note that by casting ``target.getElementType()`` to a ``RefType``, we eliminate all cases where the element type is a primitive type, that is, ``target`` is an array of primitive type: the problem we are looking for cannot arise in that case. Unlike in Java, a cast in QL never fails: if an expression cannot be cast to the desired type, it is simply excluded from the query results, which is exactly what we want. @@ -139,12 +141,12 @@ Using these new classes we can extend our query to exclude calls to ``toArray`` not ce.getExpr().(CollectionToArrayCall).getActualReturnType() = target select ce, "Potentially problematic array downcast." -➤ `See this in the query console `__. Notice that fewer results are found by this improved query. +➤ `See this in the query console on LGTM.com `__. Notice that fewer results are found by this improved query. Example: Finding mismatched contains checks ------------------------------------------- -As another example, we develop a query that finds uses of ``Collection.contains`` where the type of the queried element is unrelated to the element type of the collection, thus guaranteeing that the test will always return ``false``. +We'll now develop a query that finds uses of ``Collection.contains`` where the type of the queried element is unrelated to the element type of the collection, which guarantees that the test will always return ``false``. For example, `Apache Zookeeper `__ used to have a snippet of code similar to the following in class ``QuorumPeerConfig``: @@ -265,14 +267,14 @@ Now we are ready to write a first version of our query: not haveCommonDescendant(collEltType, argType) select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See this in the query console `__. +➤ `See this in the query console on LGTM.com `__. Improvements ~~~~~~~~~~~~ For many programs, this query yields a large number of false positive results due to type variables and wild cards: if the collection element type is some type variable ``E`` and the argument type is ``String``, for example, CodeQL will consider that the two have no common subtype, and our query will flag the call. An easy way to exclude such false positive results is to simply require that neither ``collEltType`` nor ``argType`` are instances of ``TypeVariable``. -Another source of false positives is autoboxing of primitive types: if, for example, the collection's element type is ``Integer`` and the argument is of type ``int``, predicate ``haveCommonDescendant`` will fail, since ``int`` is not a ``RefType``. Thus, our query should check that ``collEltType`` is not the boxed type of ``argType``. +Another source of false positives is autoboxing of primitive types: if, for example, the collection's element type is ``Integer`` and the argument is of type ``int``, predicate ``haveCommonDescendant`` will fail, since ``int`` is not a ``RefType``. To account for this, our query should check that ``collEltType`` is not the boxed type of ``argType``. Finally, ``null`` is special because its type (known as ```` in the CodeQL library) is compatible with every reference type, so we should exclude it from consideration. @@ -292,11 +294,11 @@ Adding these three improvements, our final query becomes: not argType.hasName("") select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See the full query in the query console `__. +➤ `See the full query in the query console on LGTM.com `__. -What next? ----------- +Further reading +--------------- -- Take a look at some of the other tutorials: :doc:`Tutorial: Expressions and statements `, :doc:`Tutorial: Navigating the call graph `, :doc:`Tutorial: Annotations `, :doc:`Tutorial: Javadoc `, and :doc:`Tutorial: Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`AST class reference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- 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 `__. diff --git a/docs/language/learn-ql/javascript/ast-class-reference.rst b/docs/language/learn-ql/javascript/ast-class-reference.rst index 1b513b2d4ec..f0a7f88fc17 100644 --- a/docs/language/learn-ql/javascript/ast-class-reference.rst +++ b/docs/language/learn-ql/javascript/ast-class-reference.rst @@ -1,5 +1,7 @@ -AST class reference -=================== +Abstract syntax tree classes for JavaScript and TypeScript +========================================================== + +CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. Statement classes ----------------- diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index a2ff4309ee0..a78dc116e37 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -1,7 +1,7 @@ -Data flow cheat sheet -===================== +Data flow cheat sheet for JavaScript +==================================== -This page describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. +This article describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. Taint tracking path queries --------------------------- @@ -34,12 +34,12 @@ This query reports flow paths which: - Step through variables, function calls, properties, strings, arrays, promises, exceptions, and steps added by `isAdditionalTaintStep `__. - End at a node matched by `isSink `__. -See also: `Global data flow `__ and :doc:`Constructing path queries <../writing-queries/path-queries>`. +See also: `Global data flow `__ and :doc:`Creating path queries <../writing-queries/path-queries>`. DataFlow module --------------- -Use data flow nodes to match program elements independently of syntax. See also: :doc:`Analyzing data flow in JavaScript/TypeScript `. +Use data flow nodes to match program elements independently of syntax. See also: :doc:`Analyzing data flow in JavaScript and TypeScript `. Predicates in the ``DataFlow::`` module: @@ -142,7 +142,7 @@ Files AST nodes --------- -See also: :doc:`AST class reference `. +See also: :doc:`Abstract syntax tree classes for JavaScript and TypeScript `. Conversion between DataFlow and AST nodes: @@ -163,7 +163,7 @@ String matching Type tracking ------------- -See also: :doc:`Type tracking tutorial `. +See also: :doc:`Using type tracking for API modeling `. Use the following template to define forward type tracking predicates: diff --git a/docs/language/learn-ql/javascript/dataflow.rst b/docs/language/learn-ql/javascript/dataflow.rst index 15cd1ad7e46..5af4fe83f2c 100644 --- a/docs/language/learn-ql/javascript/dataflow.rst +++ b/docs/language/learn-ql/javascript/dataflow.rst @@ -1,16 +1,15 @@ Analyzing data flow in JavaScript and TypeScript ================================================ +This topic describes how data flow analysis is implemented in the CodeQL libraries for JavaScript/TypeScript and includes examples to help you write your own data flow queries. + Overview -------- - -This topic describes how data flow analysis is implemented in the CodeQL libraries for JavaScript/TypeScript and includes examples to help you write your own data flow queries. -The following sections describe how to utilize the libraries for local data flow, global data flow, and taint tracking. - +The various sections in this article describe how to utilize the libraries for local data flow, global data flow, and taint tracking. As our running example, we will develop a query that identifies command-line arguments that are passed as a file path to the standard Node.js ``readFile`` function. While this is not a problematic pattern as such, it is typical of the kind of reasoning that is frequently used in security queries. -For a more general introduction to modeling data flow, see :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`. +For a more general introduction to modeling data flow, see :doc:`About data flow analysis <../intro-to-data-flow>`. Data flow nodes --------------- @@ -189,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 ~~~~~~~~~~~~~~~~~~~~~~ @@ -465,12 +468,12 @@ 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>`__) -What next? ----------- +Further reading +--------------- -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. -- Learn about writing more precise data-flow analyses in :doc:`Advanced data-flow analysis using flow labels ` +- 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 ------- diff --git a/docs/language/learn-ql/javascript/flow-labels.rst b/docs/language/learn-ql/javascript/flow-labels.rst index c693319576d..ecd8dec6b29 100644 --- a/docs/language/learn-ql/javascript/flow-labels.rst +++ b/docs/language/learn-ql/javascript/flow-labels.rst @@ -1,8 +1,13 @@ -Tutorial: Precise data-flow analysis using flow labels -====================================================== +Using flow labels for precise data flow analysis +================================================ + +You can associate flow labels with each value tracked by the flow analysis to determine whether the flow contains potential vulnerabilities. + +Overview +-------- You can use basic inter-procedural data-flow analysis and taint tracking as described in -:doc:`Analyzing data flow in JavaScript/TypeScript ` to check whether there is a path in +:doc:`Analyzing data flow in JavaScript and TypeScript ` to check whether there is a path in the data-flow graph from some source node to a sink node that does not pass through any sanitizer nodes. Another way of thinking about this is that it statically models the flow of data through the program, and associates a flag with every data value telling us whether it might have come from a @@ -390,9 +395,9 @@ tainted objects from partially tainted objects. The `Uncontrolled data used in p `_ query uses four flow labels to track whether a user-controlled string may be an absolute path and whether it may contain ``..`` components. -What next? ----------- +Further reading +--------------- -- Learn about the standard CodeQL libraries used to write queries for JavaScript in :doc:`Introducing the JavaScript libraries `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index f01a8387a18..65b19f2687d 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -1,5 +1,7 @@ -Introducing the CodeQL libraries for JavaScript -=============================================== +CodeQL library for JavaScript +============================= + +When you're analyzing a JavaScript program, you can make use of the large collection of classes in the CodeQL library for JavaScript. Overview -------- @@ -73,7 +75,7 @@ For example, the following query computes, for each folder, the number of JavaSc from Folder d select d.getRelativePath(), count(File f | f = d.getAFile() and f.getExtension() = "js") -➤ `See this in the query console `__. When you run the query on most projects, the results include folders that contain files with a ``js`` extension and folders that don't. +➤ `See this in the query console on LGTM.com `__. When you run the query on most projects, the results include folders that contain files with a ``js`` extension and folders that don't. Locations ^^^^^^^^^ @@ -134,7 +136,7 @@ As an example of a query operating entirely on the lexical level, consider the f where comma.getNextToken() instanceof CommaToken select comma, "Omitted array elements are bad style." -➤ `See this in the query console `__. If the query returns no results, this pattern isn't used in the projects that you analyzed. +➤ `See this in the query console on LGTM.com `__. If the query returns no results, this pattern isn't used in the projects that you analyzed. You can use predicate ``Locatable.getFirstToken()`` and ``Locatable.getLastToken()`` to access the first and last token (if any) belonging to an element with a source location. @@ -175,7 +177,7 @@ As an example of a query using only lexical information, consider the following from HtmlLineComment c select c, "Do not use HTML comments." -➤ `See this in the query console `__. When we ran this query on the *mozilla/pdf.js* project in LGTM.com, we found three HTML comments. +➤ `See this in the query console on LGTM.com `__. When we ran this query on the *mozilla/pdf.js* project in LGTM.com, we found three HTML comments. Syntactic level ~~~~~~~~~~~~~~~ @@ -347,7 +349,7 @@ As an example of how to use expression AST nodes, here is a query that finds exp where add = shift.getAnOperand() select add, "This expression should be bracketed to clarify precedence rules." -➤ `See this in the query console `__. When we ran this query on the *meteor/meteor* project in LGTM.com, we found many results where precedence could be clarified using brackets. +➤ `See this in the query console on LGTM.com `__. When we ran this query on the *meteor/meteor* project in LGTM.com, we found many results where precedence could be clarified using brackets. Functions ^^^^^^^^^ @@ -369,7 +371,7 @@ As an example, here is a query that finds all expression closures: where fe.getBody() instanceof Expr select fe, "Use arrow expressions instead of expression closures." -➤ `See this in the query console `__. None of the LGTM.com demo projects uses expression closures, but you may find this query gets results on other projects. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects uses expression closures, but you may find this query gets results on other projects. As another example, this query finds functions that have two parameters that bind the same variable: @@ -384,7 +386,7 @@ As another example, this query finds functions that have two parameters that bin p.getAVariable() = q.getAVariable() select fun, "This function has two parameters that bind the same variable." -➤ `See this in the query console `__. None of the LGTM.com demo projects has functions where two parameters bind the same variable. +➤ `See this in the query console on LGTM.com `__. None of the LGTM.com demo projects has functions where two parameters bind the same variable. Classes ^^^^^^^ @@ -440,7 +442,7 @@ Here is an example of a query to find declaration statements that declare the sa not ds.getTopLevel().isMinified() select ds, "Variable " + v.getName() + " is declared both $@ and $@.", d1, "here", d2, "here" -➤ `See this in the query console `__. This is not a common problem, so you may not find any results in your own projects. The *angular/angular.js* project on LGTM.com has one instance of this problem at the time of writing. +➤ `See this in the query console on LGTM.com `__. This is not a common problem, so you may not find any results in your own projects. The *angular/angular.js* project on LGTM.com has one instance of this problem at the time of writing. Notice the use of ``not ... isMinified()`` here and in the next few queries. This excludes any results found in minified code. If you delete ``and not ds.getTopLevel().isMinified()`` and re-run the query, two results in minified code in the *meteor/meteor* project are reported. @@ -467,7 +469,7 @@ As an example of a query involving properties, consider the following query that not oe.getTopLevel().isMinified() select oe, "Property " + p1.getName() + " is defined both $@ and $@.", p1, "here", p2, "here" -➤ `See this in the query console `__. Many projects have a few instances of object expressions with two identically named properties. +➤ `See this in the query console on LGTM.com `__. Many projects have a few instances of object expressions with two identically named properties. Modules ^^^^^^^ @@ -533,7 +535,7 @@ As an example, consider the following query which finds distinct function declar not g.getTopLevel().isMinified() select f, g -➤ `See this in the query console `__. Some projects declare conflicting functions of the same name and rely on platform-specific behavior to disambiguate the two declarations. +➤ `See this in the query console on LGTM.com `__. Some projects declare conflicting functions of the same name and rely on platform-specific behavior to disambiguate the two declarations. Control flow ~~~~~~~~~~~~ @@ -570,7 +572,7 @@ As an example of an analysis using basic blocks, ``BasicBlock.isLiveAtEntry(v, u not f.getStartBB().isLiveAtEntry(gv, _) select f, "This function uses " + gv + " like a local variable." -➤ `See this in the query console `__. Many projects have some variables which look as if they were intended to be local. +➤ `See this in the query console on LGTM.com `__. Many projects have some variables which look as if they were intended to be local. Data flow ~~~~~~~~~ @@ -595,7 +597,7 @@ As an example, the following query finds definitions of local variables that are not exists (VarUse use | def = use.getADef()) select def, "Dead store of local variable." -➤ `See this in the query console `__. Many projects have some examples of useless assignments to local variables. +➤ `See this in the query console on LGTM.com `__. Many projects have some examples of useless assignments to local variables. SSA ^^^ @@ -638,7 +640,7 @@ For example, here is a query that finds all invocations of a method called ``sen send.getMethodName() = "send" select send -➤ `See this in the query console `__. The query finds HTTP response sends in the `AMP HTML `__ project. +➤ `See this in the query console on LGTM.com `__. The query finds HTTP response sends in the `AMP HTML `__ project. Note that the data flow modeling in this library is intraprocedural, that is, flow across function calls and returns is *not* modeled. Likewise, flow through object properties and global variables is not modeled. @@ -703,7 +705,7 @@ As an example of a call-graph-based query, here is a query to find invocations f not exists(invk.getACallee()) select invk, "Unable to find a callee for this invocation." -➤ `See this in the query console `__ +➤ `See this in the query console on LGTM.com `__ Inter-procedural data flow ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -839,7 +841,7 @@ As an example of the use of these classes, here is a query that counts for every from NodeModule m select m, count(m.getAnImportedModule()) -➤ `See this in the query console `__. When you analyze a project, for each module you can see how many other modules it imports. +➤ `See this in the query console on LGTM.com `__. When you analyze a project, for each module you can see how many other modules it imports. NPM ^^^ @@ -868,7 +870,7 @@ As an example of the use of these classes, here is a query that identifies unuse not exists (Require req | req.getTopLevel() = pkg.getAModule() | name = req.getImportedPath().getValue()) select deps, "Unused dependency '" + name + "'." -➤ `See this in the query console `__. It is not uncommon for projects to have some unused dependencies. +➤ `See this in the query console on LGTM.com `__. It is not uncommon for projects to have some unused dependencies. React ^^^^^ @@ -895,7 +897,7 @@ For example, here is a query to find SQL queries that use string concatenation ( where ss instanceof AddExpr select ss, "Use templating instead of string concatenation." -➤ `See this in the query console `__, showing two (benign) results on `strong-arc `__. +➤ `See this in the query console on LGTM.com `__, showing two (benign) results on `strong-arc `__. Miscellaneous ~~~~~~~~~~~~~ @@ -961,7 +963,7 @@ As an example, here is a query that finds ``@param`` tags that do not specify th not exists(t.getName()) select t, "@param tag is missing name." -➤ `See this in the query console `__. Of the LGTM.com demo projects analyzed, only *Semantic-Org/Semantic-UI* has an example where the ``@param`` tag omits the name. +➤ `See this in the query console on LGTM.com `__. Of the LGTM.com demo projects analyzed, only *Semantic-Org/Semantic-UI* has an example where the ``@param`` tag omits the name. For full details on these and other classes representing JSDoc comments and type expressions, see `the API documentation `__. @@ -1026,9 +1028,9 @@ Alias nodes are represented by class `YAMLAliasNode `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. +- 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. diff --git a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst index e0c1ec748ff..672ea369479 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst @@ -1,5 +1,7 @@ -Introducing the CodeQL libraries for TypeScript -=============================================== +CodeQL library for TypeScript +============================= + +When you're analyzing a TypeScript program, you can make use of the large collection of classes in the CodeQL library for TypeScript. Overview -------- @@ -10,7 +12,7 @@ Support for analyzing TypeScript code is bundled with the CodeQL libraries for J import javascript -The :doc:`CodeQL library introduction for JavaScript ` covers most of this library, and is also relevant for TypeScript analysis. This document supplements the JavaScript documentation with the TypeScript-specific classes and predicates. +:doc:`CodeQL libraries for JavaScript ` covers most of this library, and is also relevant for TypeScript analysis. This document supplements the JavaScript documentation with the TypeScript-specific classes and predicates. Syntax ------ @@ -119,7 +121,7 @@ Select expressions that cast a value to a type parameter: where assertion.getTypeAnnotation() = param.getLocalTypeName().getAnAccess() select assertion, "Cast to type parameter." -➤ `See this in the query console `__. +➤ `See this in the query console on LGTM.com `__. Classes and interfaces ~~~~~~~~~~~~~~~~~~~~~~ @@ -134,7 +136,7 @@ The CodeQL class `ClassOrInterface `__. -Also see the documentation for classes in the `Introduction to the CodeQL libraries for JavaScript `__. +Also see the documentation for classes in the `CodeQL libraries for JavaScript `__. To select the type references to a class or an interface, use ``getTypeName()``. @@ -405,7 +407,7 @@ It is best to use `TypeName `__. +➤ `See this in the query console on LGTM.com `__. Find imported names that are used as both a type and a value: @@ -418,7 +420,7 @@ Find imported names that are used as both a type and a value: and exists (VarAccess access | access.getVariable().getADeclaration() = spec.getLocal()) select spec, "Used as both variable and type" -➤ `See this in the query console `__. +➤ `See this in the query console on LGTM.com `__. Namespace names ~~~~~~~~~~~~~~~ @@ -444,9 +446,9 @@ A `LocalNamespaceName `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. \ No newline at end of file +- 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. diff --git a/docs/language/learn-ql/javascript/ql-for-javascript.rst b/docs/language/learn-ql/javascript/ql-for-javascript.rst index d2d864cc072..5e10e9f979d 100644 --- a/docs/language/learn-ql/javascript/ql-for-javascript.rst +++ b/docs/language/learn-ql/javascript/ql-for-javascript.rst @@ -1,8 +1,9 @@ CodeQL for JavaScript ===================== +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from JavaScript codebases. + .. toctree:: - :glob: :hidden: introduce-libraries-js @@ -13,23 +14,23 @@ CodeQL for JavaScript ast-class-reference dataflow-cheat-sheet -These documents provide an overview of the CodeQL libraries for JavaScript and TypeScript and show examples of how to use them. +- `Basic JavaScript query `__: Learn to write and run a simple CodeQL query using LGTM. -- `Basic JavaScript query `__ describes how to write and run queries using LGTM. +- :doc:`CodeQL library for JavaScript `: When you're analyzing a JavaScript program, you can make use of the large collection of classes in the CodeQL library for JavaScript. -- :doc:`Introducing the CodeQL libraries for JavaScript ` introduces the standard libraries used to write queries for JavaScript code. There is an extensive CodeQL library for analyzing JavaScript code. This tutorial briefly summarizes the most important classes and predicates provided by this library. +- :doc:`CodeQL library for TypeScript `: When you're analyzing a TypeScript program, you can make use of the large collection of classes in the CodeQL library for TypeScript. -- :doc:`Introducing the CodeQL libraries for TypeScript ` introduces the standard libraries used to write queries for TypeScript code. +- :doc:`Analyzing data flow in JavaScript and TypeScript `: This topic describes how data flow analysis is implemented in the CodeQL libraries for JavaScript/TypeScript and includes examples to help you write your own data flow queries. -- :doc:`Analyzing data flow in JavaScript/TypeScript ` demonstrates how to write queries using the standard data flow and taint tracking libraries for JavaScript/TypeScript. +- :doc:`Using flow labels for precise data flow analysis `: You can associate flow labels with each value tracked by the flow analysis to determine whether the flow contains potential vulnerabilities. -- :doc:`Advanced data-flow analysis using flow labels ` shows a more advanced example of data flow analysis using flow labels. +- :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:`AST class reference ` gives an overview of all AST classes in the standard CodeQL 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:`Data flow cheat sheet ` lists parts of the CodeQL libraries that are commonly used for variant analysis and in data flow queries. +- :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. -Other resources +Further reading --------------- - For examples of how to query common JavaScript elements, see the `JavaScript cookbook `__. diff --git a/docs/language/learn-ql/javascript/type-tracking.rst b/docs/language/learn-ql/javascript/type-tracking.rst index f0dadd9ef70..d192d98472e 100644 --- a/docs/language/learn-ql/javascript/type-tracking.rst +++ b/docs/language/learn-ql/javascript/type-tracking.rst @@ -1,9 +1,10 @@ -Tutorial: API modelling using type tracking -=========================================== +Using type tracking for API modeling +==================================== -This tutorial demonstrates how to build a simple model of the Firebase API -using the CodeQL type-tracking library for JavaScript. +You can track data through an API by creating a model using the CodeQL type-tracking library for JavaScript. +Overview +-------- The type-tracking library makes it possible to track values through properties and function calls, usually to recognize method calls and properties accessed on a specific type of object. @@ -489,7 +490,7 @@ Prefer type tracking when: Prefer data-flow configurations when: - Tracking user-controlled data -- use `taint tracking `__. -- Differentiating between different kinds of user-controlled data -- use :doc:`flow labels `. +- 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>`. @@ -517,9 +518,9 @@ Type tracking is used in a few places in the standard libraries: - The `Firebase `__ and `Socket.io `__ models use type tracking to track objects coming from their respective APIs. -What next? ----------- +Further reading +--------------- -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Learn more about the query console in `Using the query console `__. -- Learn about writing precise data-flow analyses in :doc:`Advanced data-flow analysis using flow labels `. +- 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 `. diff --git a/docs/language/learn-ql/locations.rst b/docs/language/learn-ql/locations.rst index df210819ef2..a06f428bef8 100644 --- a/docs/language/learn-ql/locations.rst +++ b/docs/language/learn-ql/locations.rst @@ -1,10 +1,13 @@ -Locations and strings for QL entities +Providing locations in CodeQL queries ===================================== .. Not sure how much of this topic needs to change, and what the title should be -Providing locations -------------------- +CodeQL includes mechanisms for extracting the location of elements in a codebase. Use these mechanisms when writing custom CodeQL queries and libraries to help display information to users. + + +About locations +--------------- When displaying information to the user, LGTM needs to be able to extract location information from the results of a query. In order to do this, all QL classes which can provide location information should do this by using one of the following mechanisms: diff --git a/docs/language/learn-ql/python/control-flow-graph.rst b/docs/language/learn-ql/python/control-flow-graph.rst deleted file mode 100644 index 099c252784b..00000000000 --- a/docs/language/learn-ql/python/control-flow-graph.rst +++ /dev/null @@ -1,9 +0,0 @@ -Python control flow graph -========================= - -:doc:`Back to tutorial: control flow analysis ` - -|Python control flow graph| - -.. |Python control flow graph| image:: ../../images/python-flow-graph.png - diff --git a/docs/language/learn-ql/python/control-flow.rst b/docs/language/learn-ql/python/control-flow.rst index fc41f59c933..9291f4dc907 100644 --- a/docs/language/learn-ql/python/control-flow.rst +++ b/docs/language/learn-ql/python/control-flow.rst @@ -1,7 +1,12 @@ -Tutorial: Control flow analysis -=============================== +Analyzing control flow in Python +================================ -To analyze the `Control-flow graph `__ of a ``Scope`` we can use the two CodeQL classes ``ControlFlowNode`` and ``BasicBlock``. These classes allow you to ask such questions as "can you reach point A from point B?" or "Is it possible to reach point B *without* going through point A?". To report results we use the class ``AstNode``, which represents a syntactic element and corresponds to the source code - allowing the results of the query to be more easily understood. +You can write CodeQL queries to explore the control-flow graph of a Python program, for example, to discover unreachable code or mutually exclusive blocks of code. + +About analyzing control flow +-------------------------------------- + +To analyze the control-flow graph of a ``Scope`` we can use the two CodeQL classes ``ControlFlowNode`` and ``BasicBlock``. These classes allow you to ask such questions as "can you reach point A from point B?" or "Is it possible to reach point B *without* going through point A?". To report results we use the class ``AstNode``, which represents a syntactic element and corresponds to the source code - allowing the results of the query to be more easily understood. For more information, see `Control-flow graph `__ on Wikipedia. The ``ControlFlowNode`` class ----------------------------- @@ -19,11 +24,18 @@ To show why this complex relation is required consider the following Python code finally: close_resource() -There are many paths through the above code. There are three different paths through the call to ``close_resource();`` one normal path, one path that breaks out of the loop, and one path where an exception is raised by ``might_raise()``. (An annotated flow graph can be seen :doc:`here `.) +There are many paths through the above code. There are three different paths through the call to ``close_resource();`` one normal path, one path that breaks out of the loop, and one path where an exception is raised by ``might_raise()``. + +An annotated flow graph: + +|Python control flow graph| + +.. |Python control flow graph| image:: ../../images/python-flow-graph.png The simplest use of the ``ControlFlowNode`` and ``AstNode`` classes is to find unreachable code. There is one ``ControlFlowNode`` per path through any ``AstNode`` and any ``AstNode`` that is unreachable has no paths flowing through it. Therefore, any ``AstNode`` without a corresponding ``ControlFlowNode`` is unreachable. -**Unreachable AST nodes** +Example finding unreachable AST nodes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: ql @@ -33,9 +45,10 @@ The simplest use of the ``ControlFlowNode`` and ``AstNode`` classes is to find u where not exists(node.getAFlowNode()) select node -➤ `See this in the query console `__. The demo projects on LGTM.com all have some code that has no control flow node, and is therefore unreachable. However, since the ``Module`` class is also a subclass of the ``AstNode`` class, the query also finds any modules implemented in C or with no source code. Therefore, it is better to find all unreachable statements: +➤ `See this in the query console on LGTM.com `__. The demo projects on LGTM.com all have some code that has no control flow node, and is therefore unreachable. However, since the ``Module`` class is also a subclass of the ``AstNode`` class, the query also finds any modules implemented in C or with no source code. Therefore, it is better to find all unreachable statements. -**Unreachable statements** +Example finding unreachable statements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: ql @@ -45,15 +58,15 @@ The simplest use of the ``ControlFlowNode`` and ``AstNode`` classes is to find u where not exists(s.getAFlowNode()) select s -➤ `See this in the query console `__. This query gives fewer results, but most of the projects have some unreachable nodes. These are also highlighted by the standard query: `Unreachable code `__. +➤ `See this in the query console on LGTM.com `__. This query gives fewer results, but most of the projects have some unreachable nodes. These are also highlighted by the standard "Unreachable code" query. For more information, see `Unreachable code `__ on LGTM.com. The ``BasicBlock`` class ------------------------ -The ``BasicBlock`` class represents a `basic block `__ of control flow nodes. The ``BasicBlock`` class is not that useful for writing queries directly, but is very useful for building complex analyses, such as data flow. The reason it is useful is that it shares many of the interesting properties of control flow nodes, such as what can reach what and what `dominates `__ what, but there are fewer basic blocks than control flow nodes - resulting in queries that are faster and use less memory. +The ``BasicBlock`` class represents a basic block of control flow nodes. The ``BasicBlock`` class is not that useful for writing queries directly, but is very useful for building complex analyses, such as data flow. The reason it is useful is that it shares many of the interesting properties of control flow nodes, such as, what can reach what, and what dominates what, but there are fewer basic blocks than control flow nodes - resulting in queries that are faster and use less memory. For more information, see `Basic block `__ and `Dominator `__ on Wikipedia. -Example: Finding mutually exclusive basic blocks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Example finding mutually exclusive basic blocks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Suppose we have the following Python code: @@ -84,7 +97,8 @@ However, by that definition, two basic blocks are mutually exclusive if they are Combining these conditions we get: -**Mutually exclusive blocks within the same function** +Example finding mutually exclusive blocks within the same function +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: ql @@ -98,10 +112,11 @@ Combining these conditions we get: ) select b1, b2 -➤ `See this in the query console `__. This typically gives a very large number of results, because it is a common occurrence in normal control flow. It is, however, an example of the sort of control-flow analysis that is possible. Control-flow analyses such as this are an important aid to data flow analysis which is covered in the next tutorial. +➤ `See this in the query console on LGTM.com `__. This typically gives a very large number of results, because it is a common occurrence in normal control flow. It is, however, an example of the sort of control-flow analysis that is possible. Control-flow analyses such as this are an important aid to data flow analysis. For more information, see :doc:`Analyzing data flow and tracking tainted data in Python `. -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the tutorial topic :doc:`Taint tracking and data flow analysis in Python `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- ":doc:`Analyzing data flow and tracking tainted data in Python `" + +.. 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 c3c8a5e6eac..20e47267825 100644 --- a/docs/language/learn-ql/python/functions.rst +++ b/docs/language/learn-ql/python/functions.rst @@ -1,7 +1,9 @@ -Tutorial: Functions +Functions in Python =================== -This example uses the standard CodeQL class ``Function`` (see :doc:`Introducing the Python libraries `). +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 `." Finding all functions called "get..." ------------------------------------- @@ -24,7 +26,7 @@ Using the member predicate ``Function.getName()``, we can list all of the getter where f.getName().matches("get%") select f, "This is a function called get..." -➤ `See this in the query console `__. This query typically finds a large number of results. Usually, many of these results are for functions (rather than methods) which we are not interested in. +➤ `See this in the query console on LGTM.com `__. This query typically finds a large number of results. Usually, many of these results are for functions (rather than methods) which we are not interested in. Finding all methods called "get..." ----------------------------------- @@ -39,7 +41,7 @@ You can modify the query above to return more interesting results. As we are onl where f.getName().matches("get%") and f.isMethod() select f, "This is a method called get..." -➤ `See this in the query console `__. This finds methods whose name starts with ``"get"``, but many of those are not the sort of simple getters we are interested in. +➤ `See this in the query console on LGTM.com `__. This finds methods whose name starts with ``"get"``, but many of those are not the sort of simple getters we are interested in. Finding one line methods called "get..." ---------------------------------------- @@ -55,7 +57,7 @@ We can modify the query further to include only methods whose body consists of a and count(f.getAStmt()) = 1 select f, "This function is (probably) a getter." -➤ `See this in the query console `__. This query returns fewer results, but if you examine the results you can see that there are still refinements to be made. This is refined further in :doc:`Tutorial: Statements and expressions `. +➤ `See this in the query console on LGTM.com `__. This query returns fewer results, but if you examine the results you can see that there are still refinements to be made. This is refined further in ":doc:`Expressions and statements in Python `." Finding a call to a specific function ------------------------------------- @@ -70,14 +72,18 @@ This query uses ``Call`` and ``Name`` to find calls to the function ``eval`` - w where call.getFunc() = name and name.getId() = "eval" select call, "call to 'eval'." -➤ `See this in the query console `__. Some of the demo projects on LGTM.com use this function. +➤ `See this in the query console on LGTM.com `__. Some of the demo projects on LGTM.com use this function. The ``Call`` class represents calls in Python. The ``Call.getFunc()`` predicate gets the expression being called. ``Name.getId()`` gets the identifier (as a string) of the ``Name`` expression. Due to the dynamic nature of Python, this query will select any call of the form ``eval(...)`` regardless of whether it is a call to the built-in function ``eval`` or not. In a later tutorial we will see how to use the type-inference library to find calls to the built-in function ``eval`` regardless of name of the variable called. -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the following tutorial topics: :doc:`Statements and expressions `, :doc:`Control flow `, and :doc:`Points-to analysis and type inference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- ":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-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 54276aedd8e..d124277d0b5 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -1,17 +1,19 @@ -Introducing the CodeQL libraries for Python -=========================================== +CodeQL library for Python +========================= -There is an extensive library for analyzing CodeQL databases extracted from Python projects. The classes in this library present the data from a database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks. The library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``python.qll`` imports all the core Python library modules, so you can include the complete library by beginning your query with: +When you need to analyze a Python program, you can make use of the large collection of classes in the CodeQL library for Python. + +About the CodeQL library for Python +----------------------------------- + +The CodeQL library for each programming language uses classes with abstractions and predicates to present data in an object-oriented form. + +Each CodeQL library is implemented as a set of QL modules, that is, files with the extension ``.qll``. The module ``python.qll`` imports all the core Python library modules, so you can include the complete library by beginning your query with: .. code-block:: ql import python -The rest of this tutorial summarizes the contents of the standard libraries for Python. We recommend that you read this and then work through the practical examples in the tutorials shown at the end of the page. - -Overview of the library ------------------------ - The CodeQL library for Python incorporates a large number of classes. Each class corresponds either to one kind of entity in Python source code or to an entity that can be derived from the source code using static analysis. These classes can be divided into four categories: - **Syntactic** - classes that represent entities in the Python source code. @@ -20,16 +22,14 @@ The CodeQL library for Python incorporates a large number of classes. Each class - **Taint tracking** - classes that represent the source, sinks and kinds of taint used to implement taint-tracking queries. Syntactic classes -~~~~~~~~~~~~~~~~~ +----------------- -This part of the library represents the Python source code. The ``Module``, ``Class``, and ``Function`` classes correspond to Python modules, classes, and functions respectively, collectively these are known as ``Scope`` classes. Each ``Scope`` contains a list of statements each of which is represented by a subclass of the class ``Stmt``. Statements themselves can contain other statements or expressions which are represented by subclasses of ``Expr``. Finally, there are a few additional classes for the parts of more complex expressions such as list comprehensions. Collectively these classes are subclasses of ``AstNode`` and form an `Abstract syntax tree `__ (AST). The root of each AST is a ``Module``. - -`Symbolic information `__ is attached to the AST in the form of variables (represented by the class ``Variable``). +This part of the library represents the Python source code. The ``Module``, ``Class``, and ``Function`` classes correspond to Python modules, classes, and functions respectively, collectively these are known as ``Scope`` classes. Each ``Scope`` contains a list of statements each of which is represented by a subclass of the class ``Stmt``. Statements themselves can contain other statements or expressions which are represented by subclasses of ``Expr``. Finally, there are a few additional classes for the parts of more complex expressions such as list comprehensions. Collectively these classes are subclasses of ``AstNode`` and form an Abstract syntax tree (AST). The root of each AST is a ``Module``. Symbolic information is attached to the AST in the form of variables (represented by the class ``Variable``). For more information, see `Abstract syntax tree `__ and `Symbolic information `__ on Wikipedia. Scope ^^^^^ -A Python program is a group of modules. Technically a module is just a list of statements, but we often think of it as composed of classes and functions. These top-level entities, the module, class, and function are represented by the three CodeQL classes (`Module `__, `Class `__ and `Function `__ which are all subclasses of ``Scope``. +A Python program is a group of modules. Technically a module is just a list of statements, but we often think of it as composed of classes and functions. These top-level entities, the module, class, and function are represented by the three CodeQL classes `Module `__, `Class `__ and `Function `__ which are all subclasses of ``Scope``. - ``Scope`` @@ -47,7 +47,7 @@ All scopes are basically a list of statements, although ``Scope`` classes have a where f.getScope() instanceof Function select f -➤ `See this in the query console `__. Many projects have nested functions. +➤ `See this in the query console on LGTM.com `__. Many projects have nested functions. Statement ^^^^^^^^^ @@ -89,7 +89,7 @@ As an example, to find expressions of the form ``a+2`` where the left is a simpl where bin.getLeft() instanceof Name and bin.getRight() instanceof Num select bin -➤ `See this in the query console `__. Many projects include examples of this pattern. +➤ `See this in the query console on LGTM.com `__. Many projects include examples of this pattern. Variable ^^^^^^^^ @@ -120,7 +120,7 @@ For our first example, we can find all ``finally`` blocks by using the ``Try`` c from Try t select t.getFinalbody() -➤ `See this in the query console `__. Many projects include examples of this pattern. +➤ `See this in the query console on LGTM.com `__. Many projects include examples of this pattern. 2. Finding ``except`` blocks that do nothing '''''''''''''''''''''''''''''''''''''''''''' @@ -151,7 +151,7 @@ Both forms are equivalent. Using the positive expression, the whole query looks where forall(Stmt s | s = ex.getAStmt() | s instanceof Pass) select ex -➤ `See this in the query console `__. Many projects include pass-only ``except`` blocks. +➤ `See this in the query console on LGTM.com `__. Many projects include pass-only ``except`` blocks. Summary ^^^^^^^ @@ -237,11 +237,14 @@ Other - ``Comment`` – A comment Control flow classes -~~~~~~~~~~~~~~~~~~~~ +-------------------- -This part of the library represents the control flow graph of each ``Scope`` (classes, functions, and modules). Each ``Scope`` contains a graph of ``ControlFlowNode`` elements. Each scope has a single entry point and at least one (potentially many) exit points. To speed up control and data flow analysis, control flow nodes are grouped into `basic blocks `__. +This part of the library represents the control flow graph of each ``Scope`` (classes, functions, and modules). Each ``Scope`` contains a graph of ``ControlFlowNode`` elements. Each scope has a single entry point and at least one (potentially many) exit points. To speed up control and data flow analysis, control flow nodes are grouped into basic blocks. For more information, see `Basic block `__ on Wikipedia. -As an example, we might want to find the longest sequence of code without any branches. A ``BasicBlock`` is, by definition, a sequence of code without any branches, so we just need to find the longest ``BasicBlock``. +Example +^^^^^^^ + +If we want to find the longest sequence of code without any branches, we need to consider control flow. A ``BasicBlock`` is, by definition, a sequence of code without any branches, so we just need to find the longest ``BasicBlock``. First of all we introduce a simple predicate ``bb_length()`` which relates ``BasicBlock``\ s to their length. @@ -269,7 +272,7 @@ Using this predicate we can select the longest ``BasicBlock`` by selecting the ` where bb_length(b) = max(bb_length(_)) select b -➤ `See this in the query console `__. When we ran it on the LGTM.com demo projects, the *openstack/nova* and *ytdl-org/youtube-dl* projects both contained source code results for this query. +➤ `See this in the query console on LGTM.com `__. When we ran it on the LGTM.com demo projects, the *openstack/nova* and *ytdl-org/youtube-dl* projects both contained source code results for this query. .. pull-quote:: @@ -289,7 +292,12 @@ The classes in the control-flow part of the library are: Type-inference classes ---------------------- -The CodeQL library for Python also supplies some classes for accessing the inferred types of values. The classes ``Value`` and ``ClassValue`` allow you to query the possible classes that an expression may have at runtime. For example, which ``ClassValue``\ s are iterable can be determined using the query: +The CodeQL library for Python also supplies some classes for accessing the inferred types of values. The classes ``Value`` and ``ClassValue`` allow you to query the possible classes that an expression may have at runtime. + +Example +^^^^^^^ + +For example, which ``ClassValue``\ s are iterable can be determined using the query: **Find iterable "ClassValue"s** @@ -301,10 +309,10 @@ The CodeQL library for Python also supplies some classes for accessing the infer where cls.hasAttribute("__iter__") select cls -➤ `See this in the query console `__ This query returns a list of classes for the projects analyzed. If you want to include the results for `builtin classes `__, which do not have any Python source code, show the non-source results. +➤ `See this in the query console on LGTM.com `__ This query returns a list of classes for the projects analyzed. If you want to include the results for ``builtin`` classes, which do not have any Python source code, show the non-source results. For more information, see `builtin classes `__ in the Python documentation. Summary -~~~~~~~ +^^^^^^^ - `Value `__ @@ -312,7 +320,7 @@ Summary - ``CallableValue`` - ``ModuleValue`` -These classes are explained in more detail in :doc:`Tutorial: Points-to analysis and type inference `. +For more information about these classes, see ":doc:`Pointer analysis and type inference in Python `." Taint-tracking classes ---------------------- @@ -321,16 +329,21 @@ The CodeQL library for Python also supplies classes to specify taint-tracking an Summary -~~~~~~~ +^^^^^^^ - `TaintKind `__ - `Configuration `__ -These classes are explained in more detail in :doc:`Tutorial: Taint tracking and data flow analysis in Python `. +For more information about these classes, see ":doc:`Analyzing data flow and tracking tainted data in Python `." -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the following tutorial topics: :doc:`Functions `, :doc:`Statements and expressions `, :doc:`Control flow `, :doc:`Points-to analysis and type inference `, and :doc:`Taint tracking and data flow analysis in Python `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- ":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-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 7ae9368d02c..8fbde0d9b35 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -1,7 +1,7 @@ -Tutorial: Points-to analysis and type inference -=============================================== +Pointer analysis and type inference in Python +============================================= -This topic contains worked examples of how to write queries using the standard CodeQL library classes for Python type inference. +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. The ``Value`` class -------------------- @@ -9,7 +9,7 @@ The ``Value`` class The ``Value`` class and its subclasses ``FunctionValue``, ``ClassValue``, and ``ModuleValue`` represent the values an expression may hold at runtime. Summary -~~~~~~~ +^^^^^^^ Class hierarchy for ``Value``: @@ -22,9 +22,7 @@ Class hierarchy for ``Value``: Points-to analysis and type inference ------------------------------------- -Points-to analysis, sometimes known as `pointer analysis `__, allows us to determine which objects an expression may "point to" at runtime. - -`Type inference `__ allows us to infer what the types (classes) of an expression may be at runtime. +Points-to analysis, sometimes known as pointer analysis, allows us to determine which objects an expression may "point to" at runtime. Type inference allows us to infer what the types (classes) of an expression may be at runtime. For more information, see `Pointer analysis `__ and `Type inference `__ on Wikipedia. The predicate ``ControlFlowNode.pointsTo(...)`` shows which object a control flow node may "point to" at runtime. @@ -76,7 +74,7 @@ First we can write a query to find ordered pairs of ``except`` blocks for a ``tr ) select t, ex1, ex2 -➤ `See this in the query console `__. Many projects contain ordered ``except`` blocks in a ``try`` statement. +➤ `See this in the query console on LGTM.com `__. Many projects contain ordered ``except`` blocks in a ``try`` statement. Here ``ex1`` and ``ex2`` are both ``except`` handlers in the ``try`` statement ``t``. By using the indices ``i`` and ``j`` we can also ensure that ``ex1`` precedes ``ex2``. @@ -123,7 +121,7 @@ Combining the parts of the query we get this: ) select t, ex1, ex2 -➤ `See this in the query console `__. This query finds only one result in the demo projects on LGTM.com (`youtube-dl `__). The result is also highlighted by the standard query: `Unreachable 'except' block `__. +➤ `See this in the query console on LGTM.com `__. This query finds only one result in the demo projects on LGTM.com (`youtube-dl `__). The result is also highlighted by the standard "Unreachable 'except' block" query. For more information, see `Unreachable 'except' block `__ on LGTM.com. .. pull-quote:: @@ -158,7 +156,7 @@ Then we need to determine if the object ``iter`` is iterable. We can test ``Clas not exists(cls.lookup("__iter__")) select loop, cls -➤ `See this in the query console `__. Many projects use a non-iterable as a loop iterator. +➤ `See this in the query console on LGTM.com `__. Many projects use a non-iterable as a loop iterator. Many of the results shown will have ``cls`` as ``NoneType``. It is more informative to show where these ``None`` values may come from. To do this we use the final field of ``pointsTo``, as follows: @@ -174,7 +172,7 @@ Many of the results shown will have ``cls`` as ``NoneType``. It is more informat not cls.hasAttribute("__iter__") select loop, cls, origin -➤ `See this in the query console `__. This reports the same results, but with a third column showing the source of the ``None`` values. +➤ `See this in the query console on LGTM.com `__. This reports the same results, but with a third column showing the source of the ``None`` values. Finding calls using call-graph analysis ---------------------------------------------------- @@ -183,7 +181,7 @@ The ``Value`` class has a method ``getACall()`` which allows us to find calls to If we wish to restrict the callables to actual functions we can use the ``FunctionValue`` class, which is a subclass of ``Value`` and corresponds to function objects in Python, in much the same way as the ``ClassValue`` class corresponds to class objects in Python. -Returning to an example from :doc:`Tutorial: Functions `, we wish to find calls to the ``eval`` function. +Returning to an example from ":doc:`Functions in Python `," we wish to find calls to the ``eval`` function. The original query looked this: @@ -195,7 +193,7 @@ The original query looked this: where call.getFunc() = name and name.getId() = "eval" select call, "call to 'eval'." -➤ `See this in the query console `__. Some of the demo projects on LGTM.com have calls that match this pattern. +➤ `See this in the query console on LGTM.com `__. Some of the demo projects on LGTM.com have calls that match this pattern. There are two problems with this query: @@ -223,10 +221,12 @@ Then we can use ``Value.getACall()`` to identify calls to the ``eval`` function, call = eval.getACall() select call, "call to 'eval'." -➤ `See this in the query console `__. This accurately identifies calls to the builtin ``eval`` function even when they are referred to using an alternative name. Any false positive results with calls to other ``eval`` functions, reported by the original query, have been eliminated. +➤ `See this in the query console on LGTM.com `__. This accurately identifies calls to the builtin ``eval`` function even when they are referred to using an alternative name. Any false positive results with calls to other ``eval`` functions, reported by the original query, have been eliminated. -What next? ----------- +Further reading +--------------- -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. -- Read a description of the CodeQL database in :doc:`What's in a CodeQL database? <../database>` +- ":doc:`Analyzing control flow in Python `" +- ":doc:`Analyzing data flow and tracking tainted data in Python `" + +.. 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 680c0c374b5..04f6a2a0d75 100644 --- a/docs/language/learn-ql/python/ql-for-python.rst +++ b/docs/language/learn-ql/python/ql-for-python.rst @@ -1,37 +1,35 @@ CodeQL for Python ================= +Experiment and learn how to write effective and efficient queries for CodeQL databases generated from Python codebases. + .. toctree:: - :glob: :hidden: introduce-libraries-python functions statements-expressions - control-flow - control-flow-graph - taint-tracking pointsto-type-infer + control-flow + taint-tracking -The following tutorials and worked examples are designed to help you learn how to write effective and efficient queries for Python projects. You should work through these topics in the order displayed. +- `Basic Python query `__ : Learn to write and run a simple CodeQL query using LGTM. -- `Basic Python query `__ describes how to write and run queries using LGTM. +- :doc:`CodeQL library for Python `: When you need to analyze a Python program, you can make use of the large collection of classes in the CodeQL library for Python. -- :doc:`Introducing the CodeQL libraries for Python ` introduces the standard libraries used to write queries for Python code. +- :doc:`Functions in Python `: You can use syntactic classes from the standard CodeQL library to find Python functions and identify calls to them. -- :doc:`Tutorial: Functions ` demonstrates how to write queries using the standard CodeQL library classes for Python functions. +- :doc:`Expressions and statements in Python `: You can use syntactic classes from the CodeQL library to explore how Python expressions and statements are used in a codebase. -- :doc:`Tutorial: Statements and expressions ` demonstrates how to write queries using the standard CodeQL library classes for Python statements and expressions. +- :doc:`Analyzing control flow in Python `: You can write CodeQL queries to explore the control-flow graph of a Python program, for example, to discover unreachable code or mutually exclusive blocks of code. -- :doc:`Tutorial: Control flow ` demonstrates how to write queries using the standard CodeQL library classes for Python control flow. +- :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:`Tutorial: Points-to analysis and type inference ` demonstrates how to write queries using the standard CodeQL library classes for Python type inference. +- :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. -- :doc:`Taint tracking and data flow analysis in Python ` demonstrates how to write queries using the standard taint tracking and data flow libraries for Python. - -Other resources +Further reading --------------- -- For examples of how to query common Python elements, see the `Python cookbook `__. -- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for Python see the `CodeQL library for Python `__. +- For examples of how to query common Python elements, see the `Python cookbook `__. +- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the code used to find alerts. +- For more information about the library for JavaScript see the `CodeQL library for Python `__. diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index d3b4e68af6c..9e817d5c5c6 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -1,6 +1,8 @@ -Tutorial: Statements and expressions +Expressions and statements in Python ==================================== +You can use syntactic classes from the CodeQL library to explore how Python expressions and statements are used in a code base. + Statements ---------- @@ -37,13 +39,11 @@ Here is the full class hierarchy: - ``While`` – A ``while`` statement - ``With`` – A ``with`` statement -Example: Finding redundant 'global' statements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Example finding redundant 'global' statements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``global`` statement in Python declares a variable with a global (module-level) scope, when it would otherwise be local. Using the ``global`` statement outside a class or function is redundant as the variable is already global. -**Finding redundant global statements** - .. code-block:: ql import python @@ -52,17 +52,15 @@ The ``global`` statement in Python declares a variable with a global (module-lev where g.getScope() instanceof Module select g -➤ `See this in the query console `__. None of the demo projects on LGTM.com has a global statement that matches this pattern. +➤ `See this in the query console on LGTM.com `__. None of the demo projects on LGTM.com has a global statement that matches this pattern. The line: ``g.getScope() instanceof Module`` ensures that the ``Scope`` of ``Global g`` is a ``Module``, rather than a class or function. -Example: Finding 'if' statements with redundant branches --------------------------------------------------------- +Example finding 'if' statements with redundant branches +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An ``if`` statement where one branch is composed of just ``pass`` statements could be simplified by negating the condition and dropping the ``else`` clause. -**An 'if' statement that could be simplified** - .. code-block:: python if cond(): @@ -70,9 +68,7 @@ An ``if`` statement where one branch is composed of just ``pass`` statements cou else: do_something -To find statements like this we can run the following query: - -**Find 'if' statements with empty branches** +To find statements like this that could be simplified we can write a query. .. code-block:: ql @@ -83,7 +79,7 @@ To find statements like this we can run the following query: and forall(Stmt p | p = l.getAnItem() | p instanceof Pass) select i -➤ `See this in the query console `__. Many projects have some ``if`` statements that match this pattern. +➤ `See this in the query console on LGTM.com `__. Many projects have some ``if`` statements that match this pattern. The line: ``(l = i.getBody() or l = i.getOrelse())`` restricts the ``StmtList l`` to branches of the ``if`` statement. @@ -131,8 +127,8 @@ Each kind of Python expression has its own class. Here is the full class hierarc - ``Yield`` – A ``yield`` expression - ``YieldFrom`` – A ``yield from`` expression (Python 3.3+) -Example: Finding comparisons to integer or string literals using 'is' -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Example finding comparisons to integer or string literals using 'is' +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Python implementations commonly cache small integers and single character strings, which means that comparisons such as the following often work correctly, but this is not guaranteed and we might want to check for them. @@ -141,9 +137,7 @@ Python implementations commonly cache small integers and single character string x is 10 x is "A" -We can check for these as follows: - -**Find comparisons to integer or string literals using** ``is`` +We can check for these using a query. .. code-block:: ql @@ -154,7 +148,7 @@ We can check for these as follows: and cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal select cmp -➤ `See this in the query console `__. Two of the demo projects on LGTM.com use this pattern: *saltstack/salt* and *openstack/nova*. +➤ `See this in the query console on LGTM.com `__. Two of the demo projects on LGTM.com use this pattern: *saltstack/salt* and *openstack/nova*. The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` checks that the first comparison operator is "is" and that the first comparator is a literal. @@ -164,15 +158,11 @@ The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` che 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``). -Example: Duplicates in dictionary literals -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Example finding duplicates in dictionary literals +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If there are duplicate keys in a Python dictionary, then the second key will overwrite the first, which is almost certainly a mistake. We can find these duplicates with CodeQL, but the query is more complex than previous examples and will require us to write a ``predicate`` as a helper. -Here is the query: - -**Find duplicate dictionary keys** - .. code-block:: ql import python @@ -188,7 +178,7 @@ Here is the query: and k1 != k2 and same_key(k1, k2) select k1, "Duplicate key in dict literal" -➤ `See this in the query console `__. When we ran this query on LGTM.com, the source code of the *saltstack/salt* project contained an example of duplicate dictionary keys. The results were also highlighted as alerts by the standard `Duplicate key in dict literal `__ query. Two of the other demo projects on LGTM.com refer to duplicate dictionary keys in library files. +➤ `See this in the query console on LGTM.com `__. When we ran this query on LGTM.com, the source code of the *saltstack/salt* project contained an example of duplicate dictionary keys. The results were also highlighted as alerts by the standard "Duplicate key in dict literal" query. Two of the other demo projects on LGTM.com refer to duplicate dictionary keys in library files. For more information, see `Duplicate key in dict literal `__ on LGTM.com. The supporting predicate ``same_key`` checks that the keys have the same identifier. Separating this part of the logic into a supporting predicate, instead of directly including it in the query, makes it easier to understand the query as a whole. The casts defined in the predicate restrict the expression to the type specified and allow predicates to be called on the type that is cast-to. For example: @@ -204,12 +194,10 @@ is equivalent to The short version is usually used as this is easier to read. -Example: Finding Java-style getters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Example finding Java-style getters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Returning to the example from :doc:`Tutorial: Functions `, the query identified all methods with a single line of code and a name starting with ``get``: - -**Basic: Find Java-style getters** +Returning to the example from ":doc:`Functions in Python `," the query identified all methods with a single line of code and a name starting with ``get``. .. code-block:: ql @@ -220,9 +208,7 @@ Returning to the example from :doc:`Tutorial: Functions `, the query and count(f.getAStmt()) = 1 select f, "This function is (probably) a getter." -This basic query can be improved by checking that the one line of code is of the form ``return self.attr`` - -**Improved: Find Java-style getters** +This basic query can be improved by checking that the one line of code is a Java-style getter of the form ``return self.attr``. .. code-block:: ql @@ -234,23 +220,19 @@ This basic query can be improved by checking that the one line of code is of the and attr.getObject() = self and self.getId() = "self" select f, "This function is a Java-style getter." -➤ `See this in the query console `__. Of the demo projects on LGTM.com, only the *openstack/nova* project has examples of functions that appear to be Java-style getters. - -In this query, the condition: +➤ `See this in the query console on LGTM.com `__. Of the demo projects on LGTM.com, only the *openstack/nova* project has examples of functions that appear to be Java-style getters. .. code-block:: ql ret = f.getStmt(0) and ret.getValue() = attr -checks that the first line in the method is a return statement and that the expression returned (``ret.getValue()``) is an ``Attribute`` expression. Note that the equality ``ret.getValue() = attr`` means that ``ret.getValue()`` is restricted to ``Attribute``\ s, since ``attr`` is an ``Attribute``. - -The condition: +This condition checks that the first line in the method is a return statement and that the expression returned (``ret.getValue()``) is an ``Attribute`` expression. Note that the equality ``ret.getValue() = attr`` means that ``ret.getValue()`` is restricted to ``Attribute``\ s, since ``attr`` is an ``Attribute``. .. code-block:: ql attr.getObject() = self and self.getId() = "self" -checks that the value of the attribute (the expression to the left of the dot in ``value.attr``) is an access to a variable called ``"self"``. +This condition checks that the value of the attribute (the expression to the left of the dot in ``value.attr``) is an access to a variable called ``"self"``. Class and function definitions ------------------------------ @@ -271,8 +253,12 @@ Here is the relevant part of the class hierarchy: - ``Class`` - ``Function`` -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the following tutorial topics: :doc:`Control flow ` and :doc:`Points-to analysis and type inference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- ":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-other-resources.rst diff --git a/docs/language/learn-ql/python/taint-tracking.rst b/docs/language/learn-ql/python/taint-tracking.rst index 2ea24369bf4..bfdae7aa4eb 100644 --- a/docs/language/learn-ql/python/taint-tracking.rst +++ b/docs/language/learn-ql/python/taint-tracking.rst @@ -1,8 +1,10 @@ -Taint tracking and data flow analysis in Python -=============================================== +Analyzing data flow and tracking tainted data in Python +======================================================= -Overview --------- +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. + +About data flow and taint tracking +---------------------------------- Taint tracking is used to analyze how potentially insecure, or 'tainted' data flows throughout a program at runtime. You can use taint tracking to find out whether user-controlled input can be used in a malicious way, @@ -14,12 +16,12 @@ For example, in the assignment ``dir = path + "/"``, if ``path`` is tainted then even though there is no data flow from ``path`` to ``path + "/"``. Separate CodeQL libraries have been written to handle 'normal' data flow and taint tracking in :doc:`C/C++ <../cpp/dataflow>`, :doc:`C# <../csharp/dataflow>`, :doc:`Java <../java/dataflow>`, and :doc:`JavaScript <../javascript/dataflow>`. You can access the appropriate classes and predicates that reason about these different modes of data flow by importing the appropriate library in your query. -In Python analysis, we can use the same taint tracking library to model both 'normal' data flow and taint flow, but we are still able make the distinction between steps that preserve value and those that don't by defining additional data flow properties. +In Python analysis, we can use the same taint tracking library to model both 'normal' data flow and taint flow, but we are still able make the distinction between steps that preserve values and those that don't by defining additional data flow properties. -For further information on data flow and taint tracking with CodeQL, see :doc:`Introduction to data flow <../intro-to-data-flow>`. +For further information on data flow and taint tracking with CodeQL, see ":doc:`Introduction to data flow <../intro-to-data-flow>`." -Fundamentals of taint tracking and data flow analysis -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Fundamentals of taint tracking using data flow analysis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The taint tracking library is in the `TaintTracking `__ module. Any taint tracking or data flow analysis query has three explicit components, one of which is optional, and an implicit component. @@ -39,7 +41,7 @@ The kind of taint determines which non-value-preserving steps are possible, in a In the above example ``dir = path + "/"``, taint flows from ``path`` to ``dir`` if the taint represents a string, but not if the taint is ``None``. Limitations -~~~~~~~~~~~ +^^^^^^^^^^^ Although taint tracking is a powerful technique, it is worth noting that it depends on the underlying data flow graphs. Creating a data flow graph that is both accurate and covers a large enough part of a program is a challenge, @@ -79,6 +81,9 @@ A simple taint tracking query has the basic form: where config.hasFlow(src, sink) select sink, "Alert message, including reference to $@.", src, "string describing the source" +Example +^^^^^^^ + As a contrived example, here is a query that looks for flow from a HTTP request to a function called ``"unsafe"``. The sources are predefined and accessed by importing library ``semmle.python.web.HttpRequest``. The sink is defined by using a custom ``TaintTracking::Sink`` class. @@ -126,8 +131,8 @@ The sink is defined by using a custom ``TaintTracking::Sink`` class. -Implementing path queries -~~~~~~~~~~~~~~~~~~~~~~~~~ +Converting a taint-tracking query to a path query +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Although the taint tracking query above tells which sources flow to which sinks, it doesn't tell us how. For that we need a path query. @@ -202,8 +207,8 @@ Thus, our example query becomes: -Custom taint kinds and flows ----------------------------- +Tracking custom taint kinds and flows +------------------------------------- In the above examples, we have assumed the existence of a suitable ``TaintKind``, but sometimes it is necessary to model the flow of other objects, such as database connections, or ``None``. @@ -226,8 +231,8 @@ The ``TaintKind`` itself is just a string (a QL string, not a CodeQL entity repr which provides methods to extend flow and allow the kind of taint to change along the path. The ``TaintKind`` class has many predicates allowing flow to be modified. This simplest ``TaintKind`` does not override any predicates, meaning that it only flows as opaque data. -An example of this is the `Hard-coded credentials query `_, -which defines the simplest possible taint kind class, ``HardcodedValue``, and custom source and sink classes. +An example of this is the "Hard-coded credentials" query, +which defines the simplest possible taint kind class, ``HardcodedValue``, and custom source and sink classes. For more information, see `Hard-coded credentials `_ on LGTM.com. .. code-block:: ql @@ -251,8 +256,11 @@ which defines the simplest possible taint kind class, ``HardcodedValue``, and cu } } -What next? ----------- +Further reading +--------------- -- Experiment with the worked examples in the following tutorial topics: :doc:`Control flow ` and :doc:`Points-to analysis and type inference `. -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- ":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-other-resources.rst diff --git a/docs/language/learn-ql/ql-training.rst b/docs/language/learn-ql/ql-training.rst index 55c3d33f705..5b014ca72fc 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 `__–an example demonstrating how to develop a data flow query. - `Introduction to global data flow <../ql-training/java/global-data-flow-java.html>`__–an introduction to analyzing global data flow in Java using CodeQL. -More resources -~~~~~~~~~~~~~~ +Further reading +~~~~~~~~~~~~~~~ - If you are completely new to CodeQL, look at our introductory topics in :doc:`Learning CodeQL `. -- To find more detailed information about how to write queries for specific languages, visit the links in :ref:`Writing CodeQL queries `. -- 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 +- 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 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 b0b03321354..9eee078d18c 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -1,12 +1,17 @@ -Query writing: common performance issues -======================================== +Troubleshooting query performance +================================= + +Improve the performance of your CodeQL queries by following a few simple guidelines. + +About query performance +----------------------- This topic offers some simple tips on how to avoid common problems that can affect the performance of your queries. Before reading the tips below, it is worth reiterating a few important points about CodeQL and the QL language: - CodeQL `predicates `__ and `classes `__ are evaluated to database `tables `__. Large predicates generate large tables with many rows, and are therefore expensive to compute. -- The QL language is implemented using standard database operations and `relational algebra `__ (such as join, projection, and union). For further information about query languages and databases, see :doc:`About QL <../about-ql>`. -- Queries are evaluated *bottom-up*, which means that a predicate is not evaluated until *all* of the predicates that it depends on are evaluated. For more information on query evaluation, see `Evaluation of QL programs `__ in the QL handbook. +- The QL language is implemented using standard database operations and `relational algebra `__ (such as join, projection, and union). For further information about query languages and databases, see `About the QL language `__. +- Queries are evaluated *bottom-up*, which means that a predicate is not evaluated until *all* of the predicates that it depends on are evaluated. For more information on query evaluation, see `Evaluation of QL programs `__. Performance tips ---------------- @@ -19,9 +24,7 @@ Eliminate cartesian products The performance of a predicate can often be judged by considering roughly how many results it has. One way of creating badly performing predicates is by using two variables without relating them in any way, or only relating them using a negation. This leads to computing the `Cartesian product `__ between the sets of possible values for each variable, potentially generating a huge table of results. - This can occur if you don't specify restrictions on your variables. - For instance, consider the following predicate that checks whether a Java method ``m`` may access a field ``f``:: predicate mayAccess(Method m, Field f) { @@ -148,4 +151,4 @@ Now the structure we want is clearer. We've separated out the easy part into its Further information ------------------- -- Find out more about QL in the `QL language handbook `__ and `QL language specification `__. +- Find out more about QL in the `QL language reference `__. 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 76b419d4966..a2b1aa24804 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -1,16 +1,18 @@ -Introduction to query files -########################### +About CodeQL queries +#################### + +CodeQL queries are used to analyze code for issues related to security, correctness, maintainability, and readability. Overview ******** -Queries are programs written with CodeQL. They are designed to highlight issues related to the security, correctness, maintainability, and readability of a code base. You can also write custom queries to find specific issues relevant to your own project. Three important types of query are: +CodeQL includes queries to find the most relevant and interesting problems for each supported language. You can also write custom queries to find specific issues relevant to your own project. The important types of query are: - **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 `__. +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:: @@ -21,9 +23,8 @@ You can add custom queries to `custom query packs `__ and in the `Results view `__ in VS Code. -This topic is a basic introduction to structuring query files. You can find further information on writing queries for specific programming languages `here `__, and detailed technical information about QL in the `QL language handbook `__ and the `QL language specification `__. -For information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. - +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 `__. Basic query structure ********************* @@ -44,17 +45,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:`Constructing path queries `. +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 `. 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: -- 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. See `Using the query console `__ and `Using the extension `__ for further information. +- 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. .. pull-quote:: @@ -72,7 +73,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: @@ -83,21 +84,20 @@ When writing your own alert queries, you would typically import the standard lib - JavaScript/TypeScript: ``javascript`` - Python: ``python`` -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. See :doc:`Constructing path queries ` for further information. - -You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__ or in the `GitHub repository `__. +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 `__. Optional CodeQL classes and predicates -------------------------------------- -You can customize your analysis by defining your own predicates and classes in the query. See `Defining a predicate `__ and `Defining a class `__ for further details. +You can customize your analysis by defining your own predicates and classes in the query. For further information, see `Defining a predicate `__ and `Defining a class `__. From clause =========== The ``from`` clause declares the variables that are used in the query. Each declaration must be of the form `` ``. -For more information on the available `types `__, and to learn how to define your own types using `classes `__, see the `QL language handbook `__. +For more information on the available `types `__, and to learn how to define your own types using `classes `__, see the `QL language reference `__. Where clause ============ @@ -117,9 +117,9 @@ Select clauses for alert queries (``@kind problem``) consist of two 'columns', w - ``element``: a code element that is identified by the query, which defines where the alert is displayed. - ``string``: a message, which can also include links and placeholders, explaining why the alert was generated. -The alert message defined in the final column of the ``select`` statement can be developed to give more detail about the alert or path found by the query using links and placeholders. For further information, see :doc:`Defining 'select' statements `. +You can modify the alert message defined in the final column of the ``select`` statement to give more detail about the alert or path found by the query using links and placeholders. For further information, see :doc:`Defining the results of a query `. -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. See :doc:`Constructing path queries ` for further information. +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:: @@ -128,16 +128,34 @@ Select clauses for metric queries (``@kind metric``) consist of two 'columns', w - ``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. + +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 `__. +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 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 reference `. +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:`Constructing path queries `. +- To learn more about writing path queries, see :doc:`Creating path queries `. - Take a look at the `built-in queries `__ to see examples of the queries included in CodeQL. - Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. - For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 7b3d52515c3..4bdd328dca8 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -1,5 +1,7 @@ -Constructing path queries -######################### +Creating path queries +##################### + +You can create path queries to visualize the flow of information through a codebase. Overview ======== @@ -24,7 +26,7 @@ For more language-specific information on analyzing data flow, see: - :doc:`Analyzing data flow in C# <../csharp/dataflow>` - :doc:`Analyzing data flow in Java <../java/dataflow>` - :doc:`Analyzing data flow in JavaScript/TypeScript <../javascript/dataflow>` -- :doc:`Taint tracking and data flow analysis in Python <../python/taint-tracking>` +- :doc:`Analyzing data flow and tracking tainted data in Python <../python/taint-tracking>` Path query examples ******************* @@ -95,7 +97,7 @@ Path query metadata ******************* Path query metadata must contain the property ``@kind path-problem``–this ensures that query results are interpreted and displayed correctly. -The other metadata requirements depend on how you intend to run the query. See the section on query metadata in :doc:`Introduction to query files ` for further information. +The other metadata requirements depend on how you intend to run the query. For more information, see `Query metadata `__. Generating path explanations **************************** @@ -185,11 +187,11 @@ Each result generated by your query is displayed at a single location in the sam The ``element`` that you select in the first column depends on the purpose of the query and the type of issue that it is designed to find. This is particularly important for security issues. For example, if you believe the ``source`` value to be globally invalid or malicious it may be best to display the alert at the ``source``. In contrast, you should consider displaying the alert at the ``sink`` if you believe it is the element that requires sanitization. -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 further information, see :doc:`Defining 'select' statements `. +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? ********** -- 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. +- Take a look at the path queries for `C/C++ `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of these queries. - Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. - For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst index c3692b7fac0..86e7b1d4bdd 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -1,8 +1,10 @@ -Query help reference -******************** +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:: @@ -10,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. @@ -24,7 +26,7 @@ Each query help file provides detailed information about the purpose and use of Structure ========= -Query help files are written using an XML format called Qhelp (``.qhelp``). Query help files must have the same base name as the query they describe, and must be located in the same directory. The basic structure is as follows: +Query help files are written using a custom XML format, and stored in a file with a ``.qhelp`` extension. Query help files must have the same base name as the query they describe, and must be located in the same directory. The basic structure is as follows: .. code-block:: xml @@ -42,32 +44,32 @@ Section-level elements Section-level elements are used to group the information in the help file into sections. Many sections have a heading, either defined by a ``title`` attribute or a default value. The following section-level elements are optional child elements of the ``qhelp`` element. -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| Element | Attributes | Children | Purpose of section | -+====================+====================================+========================+===============================================================================================================================================+ -| ``example`` | None | Any block element | Demonstrate an example of code that violates the rule implemented by the query with guidance on how to fix it. Default heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``fragment`` | None | Any block element | See :ref:`Qhelp inclusion ` below. No heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``hr`` | None | None | A horizontal rule. No heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``include`` | ``src`` The Qhelp file to include. | None | Include a Qhelp file at the location of this element. See :ref:`Qhelp inclusion ` below. No heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``overview`` | None | Any block element | Overview of the purpose of the query. Typically this is the first section in a query document. No heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``recommendation`` | None | Any block element | Recommend how to address any alerts that this query identifies. Default heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``references`` | None | ``li`` elements | Reference list. Typically this is the last section in a query document. Default heading. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ -| ``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. | -+--------------------+------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| Element | Attributes | Children | Purpose of section | ++====================+=========================================+========================+===============================================================================================================================================+ +| ``example`` | None | Any block element | Demonstrate an example of code that violates the rule implemented by the query with guidance on how to fix it. Default heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``fragment`` | None | Any block element | See :ref:`Query help inclusion ` below. No heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``hr`` | None | None | A horizontal rule. No heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``include`` | ``src`` The query help file to include. | None | Include a query help file at the location of this element. See :ref:`Query help inclusion ` below. No heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``overview`` | None | Any block element | Overview of the purpose of the query. Typically this is the first section in a query document. No heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``recommendation`` | None | Any block element | Recommend how to address any alerts that this query identifies. Default heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``references`` | None | ``li`` elements | Reference list. Typically this is the last section in a query document. Default heading. | ++--------------------+-----------------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+ +| ``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 | 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 ============== -The following elements are optional child elements of the ``section``, ``example``, ``fragment``, ``recommendation``, ``overview`` and ``semmleNotes`` elements. +The following elements are optional child elements of the ``section``, ``example``, ``fragment``, ``recommendation``, ``overview``, and ``semmleNotes`` elements. .. table:: :widths: 7 20 10 25 @@ -82,7 +84,7 @@ The following elements are optional child elements of the ``section``, ``example | | | ``height`` Optional, height of the image. | | | | | | ``width`` Optional, the width of the image. | | | +----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | ``include`` | ``src`` The Qhelp file to include. | None | Include a Qhelp file at the location of this element. See :ref:`Qhelp inclusion ` below for more information. | + | ``include`` | ``src`` The query help file to include. | None | Include a query help file at the location of this element. See :ref:`Query help inclusion ` below for more information. | +----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``ol`` | None | ``li`` | Display an ordered list. See List elements below. | +----------------+----------------------------------------------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -103,12 +105,12 @@ The following elements are optional child elements of the ``section``, ``example List elements ============= -Qhelp files support two types of block elements for lists: ``ul`` and ``ol``. Both block elements support only one child elements of the type ``li``. Each ``li`` element contains either inline content or a block element. +Query help files support two types of block elements for lists: ``ul`` and ``ol``. Both block elements support only one child elements of the type ``li``. Each ``li`` element contains either inline content or a block element. Table elements ============== -The ``table`` block element is used to include a table in a Qhelp file. Each table includes a number of rows, each of which includes a number of cells. The data in the cells will be rendered as a grid. +The ``table`` block element is used to include a table in a query help file. Each table includes a number of rows, each of which includes a number of cells. The data in the cells will be rendered as a grid. +-----------+------------+--------------------+-------------------------------------------+ | Element | Attributes | Children | Purpose | @@ -157,17 +159,17 @@ Inline content is used to define the content for paragraphs, list items, table c .. _qhelp-inclusion: -Qhelp inclusion -=============== +Query help inclusion +==================== -To enable the reuse of content between different help topics, shared content can be stored in one Qhelp file and then included in a number of other Qhelp files using the ``include`` element. The shared content can stored either in the same directory as the including files, or in ``SEMMLE_DIST/docs/include``. +To reuse content between different help topics, you can store shared content in one query help file and then include it in a number of other query help files using the ``include`` element. The shared content can be stored either in the same directory as the including files, or in ``SEMMLE_DIST/docs/include``. -The ``include`` element can be used as a section or block element, the content of the Qhelp file defined by the ``src`` attribute must contain elements that are appropriate to the location of the ``include`` element. +The ``include`` element can be used as a section or block element. The content of the query help file defined by the ``src`` attribute must contain elements that are appropriate to the location of the ``include`` element. 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 @@ -175,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 Qhelp 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 @@ -191,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 @@ -207,5 +209,5 @@ The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `__ on GitHub. +- 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 51af3018fdd..15edafc9993 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -1,40 +1,45 @@ -Query metadata -============== +Metadata for CodeQL queries +=========================== + +Metadata tells users important information about CodeQL queries. You must include the correct query metadata in a query to be able to view query results in source code. + +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. +It also gives other users information about what the query results mean. For further information on query metadata, see the `query metadata style guide `__ in our `open source repository `__ on GitHub. You can also add metric queries to LGTM, but the results are not shown. To see the results of metric queries, you can run them in the query console or in `Visual Studio Code `__. .. pull-quote:: Note - 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:`Introduction to query files `. + 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 --------------- 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:`Introduction to query files ` | -| | | ``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. You can also `filter alerts `__ based on their tags. 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 `__. | -| | | ``mantainability`` | | -| | | ``readability`` | | -| | | ``security`` | | -+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 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 @@ -93,7 +98,7 @@ 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 c974f8a21d6..5531a958e3e 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -1,5 +1,10 @@ -Defining 'select' statements -============================ +Defining the results of a query +=============================== + +You can control how analysis results are displayed in source code by modifying a query's ``select`` statement. + +About query results +------------------- The information contained in the results of a query is controlled by the ``select`` statement. Part of the process of developing a useful query is to make the results clear and easy for other users to understand. When you write your own queries in the query console or in the CodeQL `extension for VS Code `__ there are no constraints on what can be selected. @@ -22,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:`Constructing path queries `. + 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 `. Developing a select statement ----------------------------- diff --git a/docs/language/learn-ql/writing-queries/writing-queries.rst b/docs/language/learn-ql/writing-queries/writing-queries.rst index e08048953c0..bdf702ded1c 100644 --- a/docs/language/learn-ql/writing-queries/writing-queries.rst +++ b/docs/language/learn-ql/writing-queries/writing-queries.rst @@ -1,57 +1,25 @@ -Writing CodeQL queries -###################### +CodeQL queries +############## -If you are familiar with CodeQL, you can modify the existing queries or write custom queries to analyze, improve, and secure your own projects. Get started by reading the information for query writers and viewing the examples provided below. - -Information for query writers -***************************** +CodeQL queries are used in code scanning analyses to find problems in source code, including potential security vulnerabilities. .. toctree:: - :glob: :hidden: introduction-to-queries - path-queries - ../intro-to-data-flow - select-statement - ../locations - debugging-queries - - -Visit `Learning CodeQL `__ to find basic information about CodeQL. This includes information about the underlying query language QL, as well as help and advice on writing queries for specific programming languages. -To learn more about the structure of query files, the key information to include when writing your own queries, and how to format them for clarity and consistency, see the following topics: - -- :doc:`Introduction to query files `–an introduction to the information contained in a basic query file. -- :doc:`Constructing path queries `–a quick guide to structuring path queries to use in security research. -- :doc:`Introduction to data flow analysis with CodeQL <../intro-to-data-flow>`–a brief introduction to modeling data flow using CodeQL. -- :doc:`Defining 'select' statements `–further detail on developing query alert messages to provide extra information in your query results. -- :doc:`Locations and strings for CodeQL entities <../locations>`–further detail on providing location information in query results. -- `CodeQL style guide on GitHub `__–a guide to formatting your queries for consistency and clarity. - -Viewing existing CodeQL queries -******************************* - -The easiest way to get started writing your own queries is to modify an existing query. To see these queries, or to try out the CodeQL query cookbooks, visit `Exploring CodeQL queries `__. -You can also find all the CodeQL queries in our `open source repository 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 -******************** - -.. toctree:: - :glob: - :hidden: - query-metadata query-help + select-statement + ../locations + ../intro-to-data-flow + path-queries + debugging-queries -Contributions to the standard queries and libraries are very welcome–see our `contributing guidelines `__ for further information. -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 our command-line tools, 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: - -.. TODO: Change "command-line tools" to a link to the CodeQL CLI? - -- :doc:`Query metadata reference ` -- `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 reference `. \ No newline at end of file +- :doc:`About CodeQL queries `: CodeQL queries are used to analyze code for issues related to security, correctness, maintainability, and readability. +- :doc:`Metadata for CodeQL queries `: Metadata tells users important information about CodeQL queries. You must include the correct query metadata in a query to be able to view query results in source code. +- :doc:`Query help files `: Query help files tell users the purpose of a query, and recommend how to solve the potential problem the query finds. +- :doc:`Defining the results of a query `: You can control how analysis results are displayed in source code by modifying a query's ``select`` statement. +- :doc:`Providing locations in CodeQL queries <../locations>`: CodeQL includes mechanisms for extracting the location of elements in a codebase. Use these mechanisms when writing custom CodeQL queries and libraries to help display information to users. +- :doc:`About data flow analysis <../intro-to-data-flow>`: Data flow analysis is used to compute the possible values that a variable can hold at various points in a program, determining how those values propagate through the program and where they are used. +- :doc:`Creating path queries `: You can create path queries to visualize the flow of information through a codebase. +- :doc:`Troubleshooting query performance `: Improve the performance of your CodeQL queries by following a few simple guidelines. diff --git a/docs/language/learn-ql/about-ql.rst b/docs/language/ql-handbook/about-the-ql-language.rst similarity index 82% rename from docs/language/learn-ql/about-ql.rst rename to docs/language/ql-handbook/about-the-ql-language.rst index 5f5362b8fd8..8cb38d05df3 100644 --- a/docs/language/learn-ql/about-ql.rst +++ b/docs/language/ql-handbook/about-the-ql-language.rst @@ -1,17 +1,15 @@ -About QL -======== +About the QL language +###################### -This section is aimed at users with a background in general purpose programming as well as in databases. For a basic introduction and information on how to get started, see :doc:`Introduction to QL ` and :doc:`Learning CodeQL <../index>`. - -QL is a declarative, object-oriented query language that is optimized to enable efficient analysis of hierarchical data structures, in particular, databases representing software artifacts. - -The queries and metrics used in LGTM are implemented using CodeQL, which uses QL to analyze code. This ensures that they can be extended or revised easily to keep up with changes in definitions of best coding practice. We continually improve existing queries as we work towards the ultimate goal of 100% precision. - -You can write queries to identify security vulnerabilities, find coding errors and bugs, or find code that breaks your team's guidelines for best practice. You can also create customized versions of the default queries to accommodate a new framework. +QL is the powerful query language that underlies CodeQL, which is used to analyze code. About query languages and databases ----------------------------------- +This section is aimed at users with a background in general purpose programming as well as in databases. For a basic introduction and information on how to get started, see `Learning CodeQL `__. + +QL is a declarative, object-oriented query language that is optimized to enable efficient analysis of hierarchical data structures, in particular, databases representing software artifacts. + A database is an organized collection of data. The most commonly used database model is a relational model which stores data in tables and SQL (Structured Query Language) is the most commonly used query language for relational databases. The purpose of a query language is to provide a programming platform where you can ask questions about information stored in a database. A database management system manages the storage and administration of data and provides the querying mechanism. A query typically refers to the relevant database entities and specifies various conditions (called predicates) that must be satisfied by the results. Query evaluation involves checking these predicates and generating the results. Some of the desirable properties of a good query language and its implementation include: @@ -41,6 +39,11 @@ When you write this process in QL, it closely resembles the above structure. Not result = count(getADescendant(p)) } +For more information about the important concepts and syntactic constructs of QL, see the individual reference topics such as :doc:`Expressions ` and :doc:`Recursion `. +The explanations and examples help you understand how the language works, and how to write more advanced QL code. + +For formal specifications of the QL language and QLDoc comments, see the :doc:`QL language specification ` and :doc:`QLDoc comment specification `. + QL and object orientation ------------------------- @@ -56,12 +59,10 @@ Here are a few prominent conceptual and functional differences between general p - QL's set-based semantics makes it very natural to process collections of values without having to worry about efficiently storing, indexing and traversing them. - In object oriented programming languages, instantiating a class involves creating an object by allocating physical memory to hold the state of that instance of the class. In QL, classes are just logical properties describing sets of already existing values. -These topics are discussed in detail in the `QL language handbook `__. +Further reading +--------------- -References ----------- - -Academic references available from the `Semmle website `__ also provide an overview of QL and its semantics. Other useful references on database query languages and Datalog: +`Academic references `__ also provide an overview of QL and its semantics. Other useful references on database query languages and Datalog: - `Database theory: Query languages `__ - `Logic Programming and Databases book - Amazon page `__ diff --git a/docs/language/ql-handbook/aliases.rst b/docs/language/ql-handbook/aliases.rst index 88675370081..03bdc835a30 100644 --- a/docs/language/ql-handbook/aliases.rst +++ b/docs/language/ql-handbook/aliases.rst @@ -4,8 +4,9 @@ Aliases ####### -An alias is an alternative name for an existing QL entity. Once you've defined an alias, -you can use that new name to refer to the entity in the current module's :ref:`namespace `. +An alias is an alternative name for an existing QL entity. + +Once you've defined an alias, you can use that new name to refer to the entity in the current module's :ref:`namespace `. Defining an alias ***************** diff --git a/docs/language/ql-handbook/annotations.rst b/docs/language/ql-handbook/annotations.rst index 8673b8194f6..9177a4197b6 100644 --- a/docs/language/ql-handbook/annotations.rst +++ b/docs/language/ql-handbook/annotations.rst @@ -4,6 +4,7 @@ Annotations ########### An annotation is a string that you can place directly before the declaration of a QL entity or name. + For example, to declare a module ``M`` as private, you could use:: private module M { @@ -248,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. @@ -291,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``. @@ -302,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/conf.py b/docs/language/ql-handbook/conf.py index 1b4887c0f06..10bda010a7e 100644 --- a/docs/language/ql-handbook/conf.py +++ b/docs/language/ql-handbook/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# QL language handbook build configuration file, created by +# QL language reference build configuration file, created by # sphinx-quickstart on Wed Feb 28 12:01:34 2018. # # This file is execfile()d with the current directory set to its @@ -17,9 +17,10 @@ ################################################################################ # -# Modified 22052019. - -# The configuration values below are specific to the QL handbook +# Modified 02042020 to rename "handbook" to "reference". +# This Sphinx project now contains both the handbook articles and the specifications. +# +# The configuration values below are specific to the QL language reference project. # 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 @@ -41,7 +42,7 @@ highlight_language = 'ql' master_doc = 'index' # Project-specific information. -project = u'QL language handbook' +project = u'QL language reference' # The version info for this project, if different from version and release in main conf.py file. # The short X.Y version. @@ -53,10 +54,10 @@ project = u'QL language handbook' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = 'QL language handbook' +html_title = 'QL language reference' # Output file base name for HTML help builder. -htmlhelp_basename = 'QL language handbook' +htmlhelp_basename = 'QL language reference' # -- Currently unused, but potentially useful, configs-------------------------------------- diff --git a/docs/language/ql-handbook/evaluation.rst b/docs/language/ql-handbook/evaluation.rst index 251b951c0e1..42520f634a2 100644 --- a/docs/language/ql-handbook/evaluation.rst +++ b/docs/language/ql-handbook/evaluation.rst @@ -3,6 +3,8 @@ Evaluation of QL programs ######################### +A QL program is evaluated in a number of different steps. + Process ******* diff --git a/docs/language/ql-handbook/expressions.rst b/docs/language/ql-handbook/expressions.rst index 57a814b958a..729bd9e4876 100644 --- a/docs/language/ql-handbook/expressions.rst +++ b/docs/language/ql-handbook/expressions.rst @@ -3,11 +3,10 @@ Expressions ########### -An expression evaluates to a set of values in QL. For example, the expression ``1 + 2`` -evaluates to the integer ``3`` and the expression ``"QL"`` evaluates to the string ``"QL"``. +An expression evaluates to a set of values and has a type. -A valid expression also has a :ref:`type `. -In the above examples, ``1 + 2`` has type ``int`` and ``"QL"`` has type ``string``. +For example, the expression ``1 + 2`` +evaluates to the integer ``3`` and the expression ``"QL"`` evaluates to the string ``"QL"``. ``1 + 2`` has :ref:`type ` ``int`` and ``"QL"`` has type ``string``. The following sections describe the expressions that are available in QL. diff --git a/docs/language/ql-handbook/formulas.rst b/docs/language/ql-handbook/formulas.rst index 45ef1302fb7..cedbfa4a4cf 100644 --- a/docs/language/ql-handbook/formulas.rst +++ b/docs/language/ql-handbook/formulas.rst @@ -3,10 +3,9 @@ Formulas ######## -Formulas define logical relations between the :ref:`free variables ` used in -:ref:`expressions `. +Formulas define logical relations between the free variables used in expressions. -Depending on the values assigned to those free variables, a formula can be true or false. +Depending on the values assigned to those :ref:`free variables `, a formula can be true or false. When a formula is true, we often say that the formula *holds*. For example, the formula ``x = 4 + 5`` holds if the value ``9`` is assigned to ``x``, but it doesn't hold for other assignments to ``x``. diff --git a/docs/language/ql-handbook/index.rst b/docs/language/ql-handbook/index.rst index 701d7d02237..ec4ab6d671e 100644 --- a/docs/language/ql-handbook/index.rst +++ b/docs/language/ql-handbook/index.rst @@ -1,29 +1,12 @@ -QL language handbook -#################### +QL language reference +##################### -Welcome to the QL language handbook! - -This document describes the main features of the QL language. The explanations and examples -help you understand how the language works, and how to write more advanced QL code. - -Each section describes an important concept or syntactic construct of QL. For an overview, see -the table of contents below. - -If you are just getting started with QL, see `Learning CodeQL `_ -for a list of the available resources. - -.. index:: specification - -For a formal specification of the QL language, see the `QL language specification -`_. - -Table of contents -***************** +Learn all about QL, the powerful query language that underlies the code scanning tool CodeQL. .. toctree:: - :numbered: 3 - :maxdepth: 3 + :maxdepth: 1 + about-the-ql-language predicates queries types @@ -37,9 +20,5 @@ Table of contents lexical-syntax name-resolution evaluation - -Index and search -**************** - -* :ref:`genindex` -* :ref:`search` + language + qldoc \ No newline at end of file diff --git a/docs/language/ql-spec/language.rst b/docs/language/ql-handbook/language.rst similarity index 99% rename from docs/language/ql-spec/language.rst rename to docs/language/ql-handbook/language.rst index d3c1cb48d48..1446e18a4f8 100644 --- a/docs/language/ql-spec/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -1,12 +1,16 @@ QL language specification ========================= +This is a formal specification for the QL language. It provides a comprehensive reference for terminology, syntax, and other technical details about QL. + +.. This ``highlight`` directive prevents code blocks in this file being highlighted as QL (the default language for this Sphinx project). + +.. highlight:: none + Introduction ------------ -This document specifies the QL language. It provides a comprehensive reference for terminology, syntax, and other technical details about QL. - -QL is a query language for Semmle databases. The data is relational: named relations hold sets of tuples. The query language is a dialect of Datalog, using stratified semantics, and it includes object-oriented classes. +QL is a query language for CodeQL databases. The data is relational: named relations hold sets of tuples. The query language is a dialect of Datalog, using stratified semantics, and it includes object-oriented classes. Notation -------- @@ -998,7 +1002,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: :: diff --git a/docs/language/ql-handbook/lexical-syntax.rst b/docs/language/ql-handbook/lexical-syntax.rst index d5f152e829e..481b0bf87ea 100644 --- a/docs/language/ql-handbook/lexical-syntax.rst +++ b/docs/language/ql-handbook/lexical-syntax.rst @@ -3,10 +3,10 @@ Lexical syntax ############## +The QL syntax includes different kinds of keywords, identifiers, and comments. + For an overview of the lexical syntax, see `Lexical syntax -`_ -in the QL language specification. In particular, you can find the list of QL keywords, the -different kinds of identifiers, and a description of comments. +`_ in the QL language specification. .. index:: comment, QLDoc .. _comments: @@ -19,7 +19,7 @@ All standard one-line and multiline comments, as described in the `QL language s compiler and are only visible in the source code. You can also write another kind of comment, namely **QLDoc comments**. These comments describe QL entities and are displayed as pop-up information in QL editors. For information about QLDoc -comments, see the `QLDoc specification `_. +comments, see the `QLDoc comment specification `_. The following example uses these three different kinds of comments:: diff --git a/docs/language/ql-handbook/name-resolution.rst b/docs/language/ql-handbook/name-resolution.rst index 6c6bd47e6fe..3e44140640e 100644 --- a/docs/language/ql-handbook/name-resolution.rst +++ b/docs/language/ql-handbook/name-resolution.rst @@ -3,6 +3,8 @@ Name resolution ############### +The QL compiler resolves names to program elements. + As in other programming languages, there is a distinction between the names used in QL code, and the underlying QL entities they refer to. @@ -240,7 +242,7 @@ and the global namespaces. (You can think of global namespaces as the enclosing Let's see what the module, type, and predicate namespaces look like in a concrete example: For example, you could define a library module ``Villagers`` containing some of the classes and predicates that -were defined in the `QL detective tutorials `_: +were defined in the `QL tutorials `_: **Villagers.qll** diff --git a/docs/language/ql-spec/qldoc.rst b/docs/language/ql-handbook/qldoc.rst similarity index 81% rename from docs/language/ql-spec/qldoc.rst rename to docs/language/ql-handbook/qldoc.rst index 62987574c12..d2ca924598e 100644 --- a/docs/language/ql-spec/qldoc.rst +++ b/docs/language/ql-handbook/qldoc.rst @@ -1,7 +1,12 @@ -QLDoc specification -=================== +QLDoc comment specification +=========================== -This document is a specification for QLDoc comments in QL source files. +This document is a formal specification for QLDoc comments. + +About QLDoc comments +-------------------- + +You can provide documentation for a QL entity by adding a QLDoc comment in the source file. The QLDoc comment is displayed as pop-up information in QL editors, for example when you hover over a predicate name. Notation -------- @@ -36,7 +41,7 @@ Content The content of a QLDoc comment is interpreted as standard Markdown, with the following extensions: -- Fenced code blocks using \`s. +- Fenced code blocks using backticks. - Automatic interpretation of links and email addresses. - Use of appropriate characters for ellipses, dashes, apostrophes, and quotes. diff --git a/docs/language/ql-handbook/queries.rst b/docs/language/ql-handbook/queries.rst index 1c21482af35..c6ef62d6b13 100644 --- a/docs/language/ql-handbook/queries.rst +++ b/docs/language/ql-handbook/queries.rst @@ -4,8 +4,7 @@ Queries ####### -Queries are the output of a QL program: they evaluate to sets of results. Indeed, we -often refer to the whole QL program as a *query*. +Queries are the output of a QL program. They evaluate to sets of results. There are two kinds of queries. For a given :ref:`query module `, the queries in that module are: - The :ref:`select clause `, if any, defined in that module. @@ -13,6 +12,8 @@ There are two kinds of queries. For a given :ref:`query module `, :ref:`namespace `. That is, they can be defined in the module itself, or imported from a different module. +We often also refer to the whole QL program as a query. + .. index:: from, where, select .. _select-clauses: diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index dfa7a8cd30f..4945978eeda 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -5,7 +5,9 @@ Types ##### -QL is a statically typed language, so each variable must have a declared **type**. A type is a set of values. +QL is a statically typed language, so each variable must have a declared type. + +A type is a set of values. For example, the type ``int`` is the set of integers. Note that a value can belong to more than one of these sets, which means that it can have more than one type. @@ -383,7 +385,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``. diff --git a/docs/language/ql-handbook/variables.rst b/docs/language/ql-handbook/variables.rst index 25b4fff1ad2..a74d492b61c 100644 --- a/docs/language/ql-handbook/variables.rst +++ b/docs/language/ql-handbook/variables.rst @@ -5,11 +5,11 @@ Variables ######### Variables in QL are used in a similar way to variables in algebra or logic. They represent sets -of values, and those values are usually restricted by a :ref:`formula `. +of values, and those values are usually restricted by a formula. This is different from variables in some other programming languages, where variables represent memory locations that may contain data. That data can also change over time. For example, in -QL, ``n = n + 1`` is an equality formula that holds only +QL, ``n = n + 1`` is an equality :ref:`formula ` that holds only if ``n`` is equal to ``n + 1`` (so in fact it does not hold for any numeric value). In Java, ``n = n + 1`` is not an equality, but an assignment that changes the value of ``n`` by adding ``1`` to the current value. diff --git a/docs/language/ql-spec/index.rst b/docs/language/ql-spec/index.rst index 4cbdc834936..cba06a87746 100644 --- a/docs/language/ql-spec/index.rst +++ b/docs/language/ql-spec/index.rst @@ -1,24 +1,5 @@ -QL specifications -################# +README +###### -.. index:: specification - - -For a formal specification of the QL language, including a description of syntax, terminology, and other technical details, please consult the QL language specification. - -For information on the terminology and syntax used in QLDoc comments, please consult the QLDoc specification. - -.. toctree:: - :maxdepth: 2 - - language - - qldoc - - -Search -****** - -.. * :ref:`genindex` - -* :ref:`search` +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 6beff0b708e..7f398da8d4b 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 handbook `__), 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 `Introduction to query files `__. 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/intro-ql-java.rst b/docs/language/ql-training/java/intro-ql-java.rst index f93a619c142..66c41df44b0 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 handbook `__), 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 `Introduction to query files `__. 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/slide-snippets/abstract-syntax-tree.rst b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst index aaa2cd23d71..e2bed2b1580 100644 --- a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst +++ b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst @@ -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/intro-ql-general.rst b/docs/language/ql-training/slide-snippets/intro-ql-general.rst index 8d6a25afad7..8c0d02d6a6f 100644 --- a/docs/language/ql-training/slide-snippets/intro-ql-general.rst +++ b/docs/language/ql-training/slide-snippets/intro-ql-general.rst @@ -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 `__. @@ -124,12 +124,12 @@ QL is: .. note:: - QL is the high-level, object-oriented logic language that underpins all CodeQL libraries and analyses. You can learn lots more about QL by visiting `Introduction to the QL language `__ and `About QL `__. + QL is the high-level, object-oriented logic language that underpins all CodeQL libraries and analyses. You can learn lots more about QL by visiting the `QL language reference `__. The key features of QL are: - 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 ed681b0398a..0bbb2c20ba4 100644 --- a/docs/language/ql-training/slide-snippets/local-data-flow.rst +++ b/docs/language/ql-training/slide-snippets/local-data-flow.rst @@ -111,8 +111,8 @@ So all references will need to be qualified (that is, ``DataFlow::Node``) A **module** is a way of organizing QL code by grouping together related predicates, classes, and (sub-)modules. They can be either explicitly declared or implicit. A query library implicitly declares a module with the same name as the QLL file. - For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language handbook. - For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language handbook. + For further information on libraries and modules in QL, see the chapter on `Modules `__ in the QL language reference. + For further information on importing QL libraries and modules, see the chapter on `Name resolution `__ in the QL language reference. Data flow graph =============== 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-other-resources.rst b/docs/language/reusables/python-other-resources.rst new file mode 100644 index 00000000000..8e9482cf230 --- /dev/null +++ b/docs/language/reusables/python-other-resources.rst @@ -0,0 +1,3 @@ +- "`QL language reference `__" +- `Python cookbook queries `__ in the Semmle wiki +- `Python queries in action `__ on LGTM.com diff --git a/docs/language/support/conf.py b/docs/language/support/conf.py index 30d7b1a3028..e88bdfce1bb 100644 --- a/docs/language/support/conf.py +++ b/docs/language/support/conf.py @@ -80,4 +80,4 @@ htmlhelp_basename = 'Supported languages and frameworks' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['read-me-project.rst'] \ No newline at end of file +exclude_patterns = ['read-me-project.rst', 'reusables/*'] \ No newline at end of file diff --git a/docs/language/support/csharp-frameworks.csv b/docs/language/support/csharp-frameworks.csv deleted file mode 100644 index 28b0b3bb06c..00000000000 --- a/docs/language/support/csharp-frameworks.csv +++ /dev/null @@ -1,9 +0,0 @@ -Name, Category -ASP.NET, Web application framework -ASP.NET Core, Web application framework -ASP.NET Razor templates, Web application framework -EntityFramework, Database ORM -EntityFramework Core, Database ORM -Json.NET, Serialization -NHibernate, Database ORM -WinForms, User interface diff --git a/docs/language/support/framework-support.rst b/docs/language/support/framework-support.rst index 71455b983ec..37d54829475 100644 --- a/docs/language/support/framework-support.rst +++ b/docs/language/support/framework-support.rst @@ -12,40 +12,4 @@ The libraries and queries in version |version| have been explicitly checked agai .. There is currently no built-in support for libraries or frameworks for C/C++. -C# built-in support -================================ - -.. csv-table:: - :file: csharp-frameworks.csv - :header-rows: 1 - :class: fullWidthTable - :widths: auto - -Java built-in support -================================== - -.. csv-table:: - :file: java-frameworks.csv - :header-rows: 1 - :class: fullWidthTable - :widths: auto - - -JavaScript and TypeScript built-in support -======================================================= - -.. csv-table:: - :file: javascript-typescript-frameworks.csv - :header-rows: 1 - :class: fullWidthTable - :widths: auto - - -Python built-in support -==================================== - -.. csv-table:: - :file: python-frameworks.csv - :header-rows: 1 - :class: fullWidthTable - :widths: auto +.. include:: reusables/frameworks.rst diff --git a/docs/language/support/java-frameworks.csv b/docs/language/support/java-frameworks.csv deleted file mode 100644 index 876d0ae111c..00000000000 --- a/docs/language/support/java-frameworks.csv +++ /dev/null @@ -1,13 +0,0 @@ -Name, Category -Hibernate, Database -iBatis / MyBatis, Database -Java Persistence API (JPA), Database -JDBC, Database -Protobuf, Serialization -Kryo deserialization, Serialization -SnakeYaml, Serialization -Spring JDBC, Database -Spring MVC, Web application framework -Struts, Web application framework -Thrift, RPC framework -XStream, Serialization diff --git a/docs/language/support/javascript-typescript-frameworks.csv b/docs/language/support/javascript-typescript-frameworks.csv deleted file mode 100644 index abed9dc5113..00000000000 --- a/docs/language/support/javascript-typescript-frameworks.csv +++ /dev/null @@ -1,23 +0,0 @@ -Name, Category -angularjs, HTML framework -axios, Network communicator -browser, Runtime environment -electron, Runtime environment -express, Server -hapi, Server -jquery, Utility library -koa, Server -lodash, Utility library -mongodb, Database -mssql, Database -mysql, Database -node, Runtime environment -postgres, Database -ramda, Utility library -react, HTML framework -request, Network communicator -sequelize, Database -socket.io, Network communicator -sqlite3, Database -superagent, Network communicator -underscore, Utility library diff --git a/docs/language/support/language-support.rst b/docs/language/support/language-support.rst index 4ffd28f3797..4aebb9957d6 100644 --- a/docs/language/support/language-support.rst +++ b/docs/language/support/language-support.rst @@ -10,4 +10,4 @@ Customers with any questions should contact their usual Semmle contact with any If you're not a customer yet, contact us at info@semmle.com with any questions you have about language and compiler support. -.. include:: versions-compilers.rst +.. include:: reusables/versions-compilers.rst diff --git a/docs/language/support/python-frameworks.csv b/docs/language/support/python-frameworks.csv deleted file mode 100644 index 7a5e78d8756..00000000000 --- a/docs/language/support/python-frameworks.csv +++ /dev/null @@ -1,11 +0,0 @@ -Name, Category -Bottle, Web framework -CherryPy, Web framework -Django, Web application framework -Falcon, Web API framework -Flask, Microframework -Pyramid, Web application framework -Tornado, Web application framework and asynchronous networking library -Turbogears, Web framework -Twisted, Networking engine -WebOb, WSGI request library diff --git a/docs/language/support/reusables/frameworks.rst b/docs/language/support/reusables/frameworks.rst new file mode 100644 index 00000000000..1b8e85e60e2 --- /dev/null +++ b/docs/language/support/reusables/frameworks.rst @@ -0,0 +1,95 @@ +.. There is currently no built-in support for libraries or frameworks for C/C++. + +C# built-in support +================================ + +.. csv-table:: + :header-rows: 1 + :class: fullWidthTable + :widths: auto + + Name, Category + ASP.NET, Web application framework + ASP.NET Core, Web application framework + ASP.NET Razor templates, Web application framework + EntityFramework, Database ORM + EntityFramework Core, Database ORM + Json.NET, Serialization + NHibernate, Database ORM + WinForms, User interface + +Java built-in support +================================== + +.. csv-table:: + :header-rows: 1 + :class: fullWidthTable + :widths: auto + + Name, Category + Hibernate, Database + iBatis / MyBatis, Database + Java Persistence API (JPA), Database + JDBC, Database + Protobuf, Serialization + Kryo deserialization, Serialization + SnakeYaml, Serialization + Spring JDBC, Database + Spring MVC, Web application framework + Struts, Web application framework + Thrift, RPC framework + XStream, Serialization + +JavaScript and TypeScript built-in support +======================================================= + +.. csv-table:: + :header-rows: 1 + :class: fullWidthTable + :widths: auto + + Name, Category + angularjs, HTML framework + axios, Network communicator + browser, Runtime environment + electron, Runtime environment + express, Server + hapi, Server + jquery, Utility library + koa, Server + lodash, Utility library + mongodb, Database + mssql, Database + mysql, Database + node, Runtime environment + postgres, Database + ramda, Utility library + react, HTML framework + request, Network communicator + sequelize, Database + socket.io, Network communicator + sqlite3, Database + superagent, Network communicator + underscore, Utility library + + + +Python built-in support +==================================== + +.. csv-table:: + :header-rows: 1 + :class: fullWidthTable + :widths: auto + + Name, Category + Bottle, Web framework + CherryPy, Web framework + Django, Web application framework + Falcon, Web API framework + Flask, Microframework + Pyramid, Web application framework + Tornado, Web application framework and asynchronous networking library + Turbogears, Web framework + Twisted, Networking engine + WebOb, WSGI request library diff --git a/docs/language/support/versions-compilers.rst b/docs/language/support/reusables/versions-compilers.rst similarity index 90% rename from docs/language/support/versions-compilers.rst rename to docs/language/support/reusables/versions-compilers.rst index 2f4091139ea..3b244e592bd 100644 --- a/docs/language/support/versions-compilers.rst +++ b/docs/language/support/reusables/versions-compilers.rst @@ -15,7 +15,7 @@ .NET Core up to 3.0","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" Go (aka Golang), "Go up to 1.14", "Go 1.11 or more recent", ``.go`` - Java,"Java 6 to 13 [4]_","javac (OpenJDK and Oracle JDK), + Java,"Java 6 to 14 [4]_","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]_" @@ -27,7 +27,7 @@ .. [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 12 can be analyzed. The analysis understands Java 12 language features. + .. [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. diff --git a/docs/ql-style-guide.md b/docs/ql-style-guide.md index a22085f50b7..495f7bf6ea9 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). diff --git a/docs/query-help-style-guide.md b/docs/query-help-style-guide.md index 58e2d93f95e..147e18d5aac 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/) @@ -16,7 +16,7 @@ Query help files must have the same base name as the query they describe and mus ### File structure and layout -Query files are written using an XML format called Qhelp, and stored in a file with a `.qhelp` extension. The basic structure is as follows: +Query help files are written using a custom XML format, and stored in a file with a `.qhelp` extension. The basic structure is as follows: ``` @@ -25,7 +25,7 @@ Query files are written using an XML format called Qhelp, and stored in a file w ``` -The header and single top-level `qhelp` element are both mandatory. +The header and single top-level `` element are both mandatory. ### Section-level elements @@ -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 the qhelp format, 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 the [Query help reference](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-help.html) on help.semmle.com. ## English style @@ -86,7 +86,7 @@ For example: >W. C. Wake, _Refactoring Workbook_, pp. 93 – 94, Addison-Wesley Professional, 2004. -Note, & symbols need to be replaced by \&. The symbol will be displayed correctly in the html files generated from the qhelp files. +Note, & symbols need to be replaced by \&. The symbol will be displayed correctly in the HTML files generated from the query help files. ### Academic papers @@ -107,11 +107,11 @@ For example: ### Referencing potential security weaknesses -If your query checks code for a CWE weakness, you should use the `@tags` element in the query file to reference the associated CWEs, as explained [here](query-metadata-style-guide.md). When you use these tags, a link to the appropriate entry from the [MITRE.org](https://cwe.mitre.org/scoring/index.html) site will automatically appear as a reference in the qhelp file. +If your query checks code for a CWE weakness, you should use the `@tags` element in the query file to reference the associated CWEs, as explained [here](query-metadata-style-guide.md). When you use these tags, a link to the appropriate entry from the [MITRE.org](https://cwe.mitre.org/scoring/index.html) site will automatically appear as a reference in the output HTML file. ## Query help example -The following example is a qhelp file for a query from the standard query suite for Java: +The following example is a query help file for a query from the standard query suite for Java: ``` -``` \ No newline at end of file +``` diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index aba7df14849..20d09ad29db 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -13,7 +13,7 @@ Query files have the extension `.ql`. Each file has two distinct areas: * [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) + * [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: 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/config/semmlecode.dbscheme b/java/ql/src/config/semmlecode.dbscheme index 054d7e823b2..2a682863863 100755 --- a/java/ql/src/config/semmlecode.dbscheme +++ b/java/ql/src/config/semmlecode.dbscheme @@ -268,6 +268,10 @@ classes( int sourceid: @class ref ); +isRecord( + unique int id: @class ref +); + interfaces( unique int id: @interface, string nodeName: string ref, diff --git a/java/ql/src/config/semmlecode.dbscheme.stats b/java/ql/src/config/semmlecode.dbscheme.stats index 165db4674b5..ae0f5e3b34f 100644 --- a/java/ql/src/config/semmlecode.dbscheme.stats +++ b/java/ql/src/config/semmlecode.dbscheme.stats @@ -9263,6 +9263,17 @@ +isRecord +100 + + +id +100 + + + + + interfaces 249736 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..658983f2437 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -0,0 +1,141 @@ +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.EndpointRequestMatcher`. + */ +class TypeEndpointRequestMatcher extends Class { + TypeEndpointRequestMatcher() { + this + .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", + "EndpointRequest$EndpointRequestMatcher") + } +} + +/** + * A call to `HttpSecurity.requestMatcher` method with argument of type + * `EndpointRequestMatcher`. + */ +class RequestMatcherCall extends MethodAccess { + RequestMatcherCall() { + getMethod().hasName("requestMatcher") and + getMethod().getDeclaringType() instanceof TypeHttpSecurity and + getArgument(0).getType() instanceof TypeEndpointRequestMatcher + } +} + +/** + * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to + * `EndpointRequestMatcher` type. + */ +class RequestMatchersCall extends MethodAccess { + RequestMatchersCall() { + getMethod().hasName("requestMatchers") and + getMethod().getDeclaringType() instanceof TypeHttpSecurity and + getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher + } +} + +/** 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 + or + // http.authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof VarAccess + | + // [...].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 + ) + ) + } +} + +/** 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 of type + * `EndpointRequestMatcher`. + */ +class RegistryRequestMatchersCall extends MethodAccess { + RegistryRequestMatchersCall() { + getMethod().hasName("requestMatchers") and + getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and + getAnArgument().getType() instanceof TypeEndpointRequestMatcher + } +} 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/qlpack.yml b/java/ql/src/qlpack.yml index f8b703f9440..7c48700e295 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-java version: 0.0.0 dbscheme: config/semmlecode.dbscheme suites: codeql-suites +extractor: java 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..820f49487b7 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 } } diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 37cc608d878..bd84637050f 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -413,7 +413,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 +844,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 @@ -1076,8 +1077,6 @@ class ConditionalExpr extends Expr, @conditionalexpr { } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * A `switch` expression. */ class SwitchExpr extends Expr, @switchexpr { @@ -1132,7 +1131,25 @@ deprecated class ParExpr extends Expr, @parexpr { /** An `instanceof` expression. */ class InstanceOfExpr extends Expr, @instanceofexpr { /** Gets the expression on the left-hand side of the `instanceof` operator. */ - Expr getExpr() { result.isNthChildOf(this, 0) } + Expr getExpr() { + if isPattern() + then result = getLocalVariableDeclExpr().getInit() + else result.isNthChildOf(this, 0) + } + + /** + * PREVIEW FEATURE in Java 14. Subject to removal in a future release. + * + * Holds if this `instanceof` expression uses pattern matching. + */ + predicate isPattern() { exists(getLocalVariableDeclExpr()) } + + /** + * PREVIEW FEATURE in Java 14. Subject to removal in a future release. + * + * Gets the local variable declaration of this `instanceof` expression if pattern matching is used. + */ + LocalVariableDeclExpr getLocalVariableDeclExpr() { result.isNthChildOf(this, 0) } /** Gets the access to the type on the right-hand side of the `instanceof` operator. */ Expr getTypeName() { result.isNthChildOf(this, 1) } @@ -1163,6 +1180,8 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr { exists(ForStmt fs | fs.getAnInit() = this | result.isNthChildOf(fs, 0)) or exists(EnhancedForStmt efs | efs.getVariable() = this | result.isNthChildOf(efs, -1)) + or + exists(InstanceOfExpr ioe | this.getParent() = ioe | result.isNthChildOf(ioe, 1)) } /** Gets the name of the variable declared by this local variable declaration expression. */ 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/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 2a5f94ef781..fa303a7c3ee 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -417,8 +417,6 @@ class SwitchCase extends Stmt, @case { SwitchStmt getSwitch() { result.getACase() = this } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * Gets the switch expression to which this case belongs, if any. */ SwitchExpr getSwitchExpr() { result.getACase() = this } @@ -432,8 +430,6 @@ class SwitchCase extends Stmt, @case { } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * Holds if this `case` is a switch labeled rule of the form `... -> ...`. */ predicate isRule() { @@ -443,15 +439,11 @@ class SwitchCase extends Stmt, @case { } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * Gets the expression on the right-hand side of the arrow, if any. */ Expr getRuleExpression() { result.getParent() = this and result.getIndex() = -1 } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * Gets the statement on the right-hand side of the arrow, if any. */ Stmt getRuleStatement() { result.getParent() = this and result.getIndex() = -1 } @@ -465,8 +457,6 @@ class ConstCase extends SwitchCase { Expr getValue() { result.getParent() = this and result.getIndex() = 0 } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * Gets the `case` constant at the specified index. */ Expr getValue(int i) { result.getParent() = this and result.getIndex() = i and i >= 0 } @@ -624,8 +614,6 @@ class BreakStmt extends Stmt, @breakstmt { } /** - * PREVIEW FEATURE in Java 13. Subject to removal in a future release. - * * A `yield` statement. */ class YieldStmt extends Stmt, @yieldstmt { diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index 410d83818cc..fb2383b8e13 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 diff --git a/java/ql/src/semmle/code/java/Type.qll b/java/ql/src/semmle/code/java/Type.qll index f08c5a5eea4..4f29ea94bd7 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -615,6 +615,15 @@ class Class extends RefType, @class { } } +/** + * PREVIEW FEATURE in Java 14. Subject to removal in a future release. + * + * A record declaration. + */ +class Record extends Class { + Record() { isRecord(this) } +} + /** An intersection type. */ class IntersectionType extends RefType, @class { IntersectionType() { @@ -628,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/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/Nullness.qll b/java/ql/src/semmle/code/java/dataflow/Nullness.qll index 644790bea6b..1679ce6b9b9 100644 --- a/java/ql/src/semmle/code/java/dataflow/Nullness.qll +++ b/java/ql/src/semmle/code/java/dataflow/Nullness.qll @@ -579,7 +579,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 +701,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/TypeFlow.qll b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll index 24cf918a9b7..b5cea656a38 100644 --- a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll @@ -365,12 +365,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..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -251,15 +251,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 +289,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 + nodeCandFwd1IsStored(f, config) and not inBarrier(node, config) ) or @@ -317,13 +313,34 @@ 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 f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + pragma[nomagic] private predicate nodeCandFwd1ReturnPosition( ReturnPosition pos, boolean fromArg, Configuration config @@ -335,43 +352,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 +368,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 +379,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) { @@ -435,55 +422,43 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) // store exists(Content f | nodeCand1Store(f, node, toReturn, config) and - readCand1(f, config) + nodeCand1IsRead(f, config) ) or // read exists(Node mid, Content f | - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, 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`. */ pragma[nomagic] -private predicate readCand1(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content f, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - readDirect(node, f, mid) and - storeCandFwd1(f, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -492,8 +467,8 @@ pragma[nomagic] private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { exists(Node mid | nodeCand1(mid, toReturn, config) and - storeCandFwd1(f, unbind(config)) and - storeDirect(node, f, mid) + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) ) } @@ -501,13 +476,29 @@ private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configu * Holds if `f` 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 +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and nodeCand1Store(f, _, _, 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 +506,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 +543,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 +557,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) @@ -576,419 +570,73 @@ private predicate parameterThroughFlowCand(ParameterNode p, Configuration config pragma[nomagic] private predicate store(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(f, config) and nodeCand1(n2, unbind(config)) and - ( - storeDirect(n1, f, n2) or - argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2) - ) + store(n1, f, n2) } pragma[nomagic] private predicate read(Node n1, Content f, Node n2, Configuration config) { - readStoreCand1(f, config) and + nodeCand1IsReadAndStored(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) - ) + read(n1, f, n2) } 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 predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, 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[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, 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 - 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) - ) -} - -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 +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config ) { - argumentFlowsThrough(arg.getNode(), out.getNode(), _, t, TSummaryTaint(), config) + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, 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[noinline] -private ReturnPosition getReturnPosition1(ReturnNodeExt node, Configuration config) { - result = getReturnPosition(node) and - nodeCand1(node, 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 +647,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,117 +659,126 @@ 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, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and stored = true ) or // read exists(Content f | - nodeCandFwd2Read(f, node, fromArg, config) and - storeCandFwd2(f, stored, config) + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, 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) + ) ) ) } @@ -1130,86 +787,148 @@ private predicate nodeCandFwd2(NodeExt node, boolean fromArg, boolean stored, Co * Holds if `f` 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 f, 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 + store(mid, f, 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 f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, 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) + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, 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 f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, 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() ) } @@ -1217,32 +936,36 @@ private predicate nodeCand2(NodeExt node, boolean toReturn, boolean read, Config * Holds if `f` 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 f, 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, f, mid, config) and + nodeCandFwd2IsStored(f, 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 f, 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)) + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) ) } +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ pragma[nomagic] -private predicate storeCand2(Content f, boolean stored, Configuration conf) { - exists(NodeExt node | - nodeCand2Store(f, node, _, stored, conf) and - nodeCand2(node, _, stored, conf) +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) ) } @@ -1251,29 +974,76 @@ private predicate storeCand2(Content f, boolean stored, Configuration conf) { * covered by `nodeCand2`. */ pragma[noinline] -private predicate readStoreCand(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { exists(boolean apNonEmpty | - storeCand2(f, apNonEmpty, conf) and - readCand2(f, apNonEmpty, conf) + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) ) } -private predicate nodeCand2(NodeExt node, Configuration config) { nodeCand2(node, _, _, config) } +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + 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 flowOutOfCallableNodeCand2( - NodeExt node1, NodeExt node2, boolean allowsFieldFlow, Configuration config +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config ) { - flowOutOfCallableNodeCand1(node1, node2, allowsFieldFlow, config) and + 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 +1054,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 +1072,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 +1086,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 +1109,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,307 +1146,365 @@ 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 f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - readStoreCand(f, unbind(config)) + nodeCand2IsReadAndStored(f, 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, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) 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(f, 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 + 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 + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and apf.headUsesContent(f) ) or + // read exists(Content f | - flowCandFwdRead(f, node, fromArg, config) and - consCandFwd(f, apf, config) and - nodeCand2(node, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, 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 +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and compatibleTypes(apf.getType(), f.getType()) ) } 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 +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) ) } +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 data can flow from a source to `node` with the given `apf` and - * from there flow to a sink. + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. */ 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 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 `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( + 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 - toReturn = false + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() ) or - exists(NodeExt mid, AccessPathFrontNil nil | - flowCandFwd(node, _, apf, config) and - additionalJumpStepExt(node, mid, config) and - flowCand(mid, _, nil, config) and + 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 - 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 + // store exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, apf0, config) and + flowCandStore(node, f, toReturn, returnApf, apf0, config) and apf0.headUsesContent(f) and - consCand(f, apf, config) + flowCandConsCand(f, apf, config) ) or + // read exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, apf0, config) and - consCandFwd(f, apf0, config) and + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and apf.headUsesContent(f) ) + 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 + // 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 flowCandRead( - NodeExt node, Content f, boolean toReturn, AccessPathFront apf0, Configuration config + Node node, Content f, 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 | + readCand2(node, f, 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, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config ) { - exists(NodeExt mid | - storeExtCand2(node, f, mid, config) and - flowCand(mid, toReturn, apf0, config) + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, 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 +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and apf0.headUsesContent(f) and - flowCandRead(n, f, _, apf, config) + flowCandRead(n, f, _, _, 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 + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or TConsCons(Content f1, Content f2, int len) { - consCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] } /** @@ -1778,292 +1611,396 @@ private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } /** Gets the access path obtained by pushing `f` onto `ap`. */ private AccessPath push(Content f, AccessPath ap) { ap = pop(f, 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 + // store exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, config) and + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and ap = push(f, ap0) ) or + // read exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, config) and - flowConsCandFwd(f, apf, ap, config) + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // 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, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config ) { - exists(NodeExt mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and flowFwdStore1(mid, f, node, apf0, apf, config) ) } pragma[nomagic] private predicate flowFwdStore0( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, Configuration config + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config ) { - storeExtCand2(mid, f, node, config) and - flowCand(mid, _, apf0, config) + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) } pragma[noinline] private predicate flowFwdStore1( - NodeExt mid, Content f, NodeExt node, AccessPathFront apf0, AccessPathFrontHead apf, + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { flowFwdStore0(mid, f, node, apf0, config) and - consCand(f, apf0, config) and + flowCandConsCand(f, apf0, config) and apf.headUsesContent(f) and - flowCand(node, _, apf, unbind(config)) + flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] private predicate flowFwdRead( - NodeExt node, Content f, AccessPath ap0, boolean fromArg, Configuration config + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config ) { - exists(NodeExt mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, apf0, ap0, config) and - readExtCand2(mid, f, node, config) and + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and apf0.headUsesContent(f) and - flowCand(node, _, _, unbind(config)) + flowCand(node, _, _, _, unbind(config)) ) } pragma[nomagic] -private predicate flowConsCandFwd( +private predicate flowFwdConsCand( Content f, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(NodeExt n | - flowFwd(n, _, apf, ap, config) and + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and flowFwdStore1(n, f, _, apf, _, config) ) } -/** - * Holds if data can flow from a source to `node` with the given `ap` and - * from there flow to a sink. - */ -private predicate flow(NodeExt node, boolean toReturn, AccessPath ap, Configuration config) { - flow0(node, toReturn, 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 - toReturn = false and - ap instanceof AccessPathNil - or - exists(NodeExt mid | - localFlowBigStepExt(node, mid, true, _, config) and - flow(mid, toReturn, ap, config) - ) - or - exists(NodeExt mid, AccessPathNil nil | - flowFwd(node, _, _, ap, config) and - localFlowBigStepExt(node, mid, false, _, config) and - flow(mid, toReturn, nil, config) and - ap instanceof AccessPathNil - ) - or - exists(NodeExt mid | - jumpStepExt(node, mid, config) and - flow(mid, _, ap, config) and - toReturn = false - ) - 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) +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 storeFwd( - NodeExt node1, Content f, NodeExt node2, AccessPath ap, AccessPath ap0, Configuration config +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config ) { - storeExtCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, config) and + 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 `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( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +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(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + 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(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(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, 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 + // 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 storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and ap0 = push(f, ap) } pragma[nomagic] private predicate flowStore( - Content f, NodeExt node, boolean toReturn, AccessPath ap, Configuration config + Content f, 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, f, 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, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readExtCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, config) and + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and ap0 = pop(f, ap) and - flowConsCandFwd(f, _, ap0, unbind(config)) + flowFwdConsCand(f, _, 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) + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, 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 +2050,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) { @@ -2293,17 +2230,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 +2256,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(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2331,23 +2269,9 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() } -pragma[nomagic] -private predicate pathIntoLocalStep( - PathNodeMid mid, Node midnode, CallContext cc, DataFlowCallable enclosing, SummaryCtx sc, - AccessPath ap0, Configuration conf -) { - midnode = mid.getNode() and - cc = mid.getCallContext() and - conf = mid.getConfiguration() and - localFlowBigStep(midnode, _, _, _, conf, _) and - enclosing = midnode.getEnclosingCallable() and - sc = mid.getSummaryCtx() and - ap0 = mid.getAp() -} - pragma[nomagic] private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - readDirect(node1, f, node2) and + read(node1, f, node2) and flow(node2, config) } @@ -2360,7 +2284,7 @@ private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Conte pragma[nomagic] private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - storeDirect(node1, f, node2) and + store(node1, f, node2) and flow(node2, config) } @@ -2399,11 +2323,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 +2339,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 +2363,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 +2438,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 +2479,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 @@ -2854,7 +2775,7 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and - storeDirect(mid.getNode(), f, node) and + store(mid.getNode(), f, node) and ap2.getHead() = f and ap2.len() = unbindInt(ap1.len() + 1) and compatibleTypes(ap1.getType(), f.getType()) 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..852f54974e2 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,140 @@ private module Cached { /** * The final flow-through calculation: * - * - Input/output access paths are abstracted with a `ContentOption` parameter + * - Input access paths are abstracted with a `ContentOption` parameter * that represents the head of the access path. `TContentNone()` means that * the access path is unrestricted. * - 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. * * `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 any). */ - private predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow0(p, node, contentIn, contentOut) and + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and if node instanceof CastingNode then // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, ContentOption contentOut - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - contentOut = TContentNone() + contentIn = TContentNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, contentOut) and + parameterValueFlow(p, mid, contentIn) 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() - ) - 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()) + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) ) 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, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, 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, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, ContentOption contentOut + ParameterNode p, ArgumentNode arg, ContentOption contentIn ) { - parameterValueFlow(p, arg, contentIn, contentOut) and - Cand::argumentValueFlowsThroughCand(arg, _, _, _) + parameterValueFlow(p, arg, contentIn) 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, ContentOption contentIn ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, _, kind, contentIn, contentOut) + parameterValueFlowReturn(param, kind, contentIn) ) } /** - * Holds if `arg` flows to `out` through `call` using only value-preserving steps, + * Holds if `arg` flows to `out` through a call using only value-preserving steps, * 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). + * `contentIn` describes the content of `arg` that can flow to `out` (if any). */ - 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, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) | // normal flow through contentIn = TContentNone() and - contentOut = TContentNone() 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)) - ) ) } - /** - * Holds if `p` can flow to the pre-update node associated with post-update - * node `n`, in the same callable, using only value-preserving steps. - */ - cached - predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), TContentNone()) - } - - pragma[nomagic] - private predicate parameterValueFlowsToPostUpdate( - ParameterNode p, PostUpdateNode n, ContentOption contentIn, ContentOption contentOut - ) { - parameterValueFlow(p, n, contentIn, contentOut) and - contentOut.hasContent() - } - /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps. * * `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). + * node (if any). */ - cached - predicate parameterValueFlowReturn( - ParameterNode p, Node ret, ReturnKindExt kind, ContentOption contentIn, - ContentOption contentOut + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn ) { - 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, contentIn) 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(), TContentNone()) + } + /** * Holds if data can flow from `node1` to `node2` via a direct assignment to * `f`. @@ -469,14 +340,14 @@ 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) { + predicate store(Node node1, Content f, Node node2) { storeStep(node1, f, node2) and readStep(_, f, _) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(_, n2, TContentSome(f), TContentNone(), n1) + argumentValueFlowsThrough(n2, TContentSome(f), n1) or readStep(n2, f, n1) ) @@ -520,6 +391,21 @@ 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 TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) } /** @@ -529,8 +415,7 @@ 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 } } @@ -538,7 +423,7 @@ newtype TContentOption = TContentNone() or TContentSome(Content f) -class ContentOption extends TContentOption { +private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } predicate hasContent() { exists(this.getContent()) } @@ -678,6 +563,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 +585,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 +597,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 +611,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 +678,58 @@ 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())) + } +} + +/** + * 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(Content f) { this = TFrontHead(f) } +} + +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 } +} + +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 } +} + +/** 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/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index a1aa335fefc..0894e11bfaa 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -434,7 +434,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 diff --git a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll index 0b2b871e129..0ef6da8b150 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 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/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/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/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..b554a7bac7e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -0,0 +1,40 @@ +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()); + } +} 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/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/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..5b94a086e8f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -0,0 +1,15 @@ +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 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/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/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..22ee7be5a12 --- /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 + argumentValueFlowsThrough(n1, TContentSome(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/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/guards12/options b/java/ql/test/library-tests/guards12/options index 99827347b32..3f12170222c 100644 --- a/java/ql/test/library-tests/guards12/options +++ b/java/ql/test/library-tests/guards12/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args --enable-preview -source 13 -target 13 +//semmle-extractor-options: --javac-args -source 14 -target 14 diff --git a/java/ql/test/library-tests/structure/DeclaresMember.expected b/java/ql/test/library-tests/structure/DeclaresMember.expected index f4a9c678cc3..32c5f05891b 100644 --- a/java/ql/test/library-tests/structure/DeclaresMember.expected +++ b/java/ql/test/library-tests/structure/DeclaresMember.expected @@ -28,7 +28,6 @@ | LocalClass | LocalClass | | LocalClass | n | | MemberClass | MemberClass | -| Object | | | Object | Object | | Object | clone | | Object | equals | diff --git a/java/ql/test/qlpack.yml b/java/ql/test/qlpack.yml index d4b46d7d2b0..75a27d69080 100644 --- a/java/ql/test/qlpack.yml +++ b/java/ql/test/qlpack.yml @@ -1,3 +1,4 @@ name: codeql-java-tests version: 0.0.0 libraryPathDependencies: codeql-java +extractor: java 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/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/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/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/old.dbscheme b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/old.dbscheme new file mode 100755 index 00000000000..054d7e823b2 --- /dev/null +++ b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/old.dbscheme @@ -0,0 +1,950 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * 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: + * + * javac A.java B.java C.java + */ + 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 + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#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( + unique 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 +); + +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 +); + +/* + * External artifacts + */ + +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 +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref // deprecated +); + +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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @typeorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @typeorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[classid] #keyset[parent] +isLocalClass( + int classid: @class ref, + int parent: @localclassdeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @typeorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localclassdeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +; + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@typeorpackage = @type | @package; + +@typeorcallable = @type | @callable; +@classorinterface = @interface | @class; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; +@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field | + @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl; + +@modifiable = @member_modifiable| @param | @localvar ; + +@member_modifiable = @class | @interface | @method | @constructor | @field ; + +@member = @method | @constructor | @field | @reftype ; + +@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception + | @boundedtype | @typebound | @array | @primitive + | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText + | @xmllocatable; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; diff --git a/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/semmlecode.dbscheme b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/semmlecode.dbscheme new file mode 100755 index 00000000000..2a682863863 --- /dev/null +++ b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/semmlecode.dbscheme @@ -0,0 +1,954 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * 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: + * + * javac A.java B.java C.java + */ + 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 + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#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( + unique 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 +); + +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 +); + +/* + * External artifacts + */ + +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 +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref // deprecated +); + +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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +isRecord( + unique int id: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @typeorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @typeorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[classid] #keyset[parent] +isLocalClass( + int classid: @class ref, + int parent: @localclassdeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @typeorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localclassdeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +; + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@typeorpackage = @type | @package; + +@typeorcallable = @type | @callable; +@classorinterface = @interface | @class; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; +@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field | + @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl; + +@modifiable = @member_modifiable| @param | @localvar ; + +@member_modifiable = @class | @interface | @method | @constructor | @field ; + +@member = @method | @constructor | @field | @reftype ; + +@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception + | @boundedtype | @typebound | @array | @primitive + | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText + | @xmllocatable; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; diff --git a/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/upgrade.properties b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/upgrade.properties new file mode 100644 index 00000000000..d42c96673ad --- /dev/null +++ b/java/upgrades/054d7e823b2c5b93bf2a14d5c22a107934fbc133/upgrade.properties @@ -0,0 +1,2 @@ +description: Java 14: add `isRecord` relation +compatibility: backwards 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/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/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/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/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..cfbc3c08069 --- /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..3bc9e36267d --- /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-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/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/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/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..d00c63acdf6 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 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 1f587affc85..7612a1d52f2 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -2,3 +2,4 @@ name: codeql-javascript version: 0.0.0 dbscheme: semmlecode.javascript.dbscheme suites: codeql-suites +extractor: javascript diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index 38d049c088d..c0ce9ae0c46 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -56,10 +56,16 @@ class AmdModuleDefinition extends CallExpr { */ pragma[nomagic] DataFlow::SourceNode getFactoryNode() { - result.flowsToExpr(getLastArgument()) and + result = getFactoryNodeInternal() and result instanceof DataFlow::ValueNode } + private DataFlow::Node getFactoryNodeInternal() { + // To avoid recursion, this should not depend on `SourceNode`. + result = DataFlow::valueNode(getLastArgument()) or + result = getFactoryNodeInternal().getAPredecessor() + } + /** Gets the expression defining this module. */ Expr getModuleExpr() { exists(DataFlow::Node f | f = getFactoryNode() | @@ -108,7 +114,7 @@ class AmdModuleDefinition extends CallExpr { * Gets the `i`th parameter of the factory function of this module. */ private SimpleParameter getFactoryParameter(int i) { - getFactoryNode().(DataFlow::FunctionNode).getParameter(i) = DataFlow::parameterNode(result) + getFactoryNodeInternal().asExpr().(Function).getParameter(i) = result } /** @@ -284,6 +290,7 @@ private class AmdDependencyImport extends Import { * ``` */ class AmdModule extends Module { + cached AmdModule() { strictcount(AmdModuleDefinition def | amdModuleTopLevel(def, this)) = 1 } /** Gets the definition of this module. */ diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index b1cbe224764..6c80546abb2 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 `