Compare commits

..

1 Commits

Author SHA1 Message Date
James Fletcher
bb44a76d5e Merge pull request #3138 from jf205/recent-changes
docs: fix links in Python articles (rc/1.23)
2020-03-27 08:17:03 +00:00
3384 changed files with 89472 additions and 178507 deletions

View File

@@ -2,4 +2,5 @@
"*/ql/test/qlpack.yml",
"*/upgrades/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] }
"misc/suite-helpers/qlpack.yml",
"codeql/.codeqlmanifest.json" ] }

24
.github/labeler.yml vendored
View File

@@ -1,24 +0,0 @@
"C++":
- cpp/**/*
- change-notes/**/*cpp*
"C#":
- csharp/**/*
- change-notes/**/*csharp*
Java:
- java/**/*
- change-notes/**/*java.*
JS:
- javascript/**/*
- change-notes/**/*javascript*
Python:
- python/**/*
- change-notes/**/*python*
documentation:
- "**/*.qhelp"
- "**/*.md"
- docs/**/*

7
.gitignore vendored
View File

@@ -1,7 +1,6 @@
# editor and OS artifacts
*~
.DS_STORE
*.swp
# query compilation caches
.cache
@@ -14,11 +13,5 @@
.vs/*
!.vs/VSWorkspaceSettings.json
# Byte-compiled python files
*.pyc
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
/codeql/
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
.vscode

View File

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

13
COPYRIGHT Normal file
View File

@@ -0,0 +1,13 @@
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.

189
LICENSE
View File

@@ -1,21 +1,176 @@
MIT License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2006-2020 GitHub, Inc.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
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:
1. Definitions.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
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.
"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

View File

@@ -1,6 +1,6 @@
# CodeQL
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide.
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com), and the other products that [Semmle](https://semmle.com) makes available to its customers worldwide.
## How do I learn CodeQL and run queries?
@@ -9,8 +9,8 @@ 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/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.
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.
## 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 [Apache License 2.0](LICENSE) by [Semmle](https://semmle.com).

View File

@@ -1,84 +0,0 @@
# Improvements to C/C++ analysis
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** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| Implicit function declarations (`cpp/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql`) | correctness, maintainability | This query finds calls to undeclared functions that are compiled by a C compiler. Results are shown on LGTM by default. |
## 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. |
| 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 | 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`),<br> Possibly wrong buffer size in string copy (`cpp/bad-strncpy-size`),<br> 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 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.
* 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`.

View File

@@ -1,48 +0,0 @@
# Improvements to C# analysis
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. 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** |
|------------------------------|------------------------|-----------------------------------|
| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. |
| 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. |
| 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
* Tuple expressions, for example `(int,bool)` in `default((int,bool))` are now extracted correctly.
* Expression nullability flow state is extracted.
* Implicitly typed `stackalloc` expressions are now extracted correctly.
* The difference between `stackalloc` array creations and normal array creations is extracted.
## 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 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, emails, and cookies.

View File

@@ -1,43 +0,0 @@
# Improvements to Java analysis
The following changes in version 1.24 affect Java analysis in all applications.
## General improvements
* 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
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| Disabled Spring CSRF protection (`java/spring-disabled-csrf-protection`) | security, external/cwe/cwe-352 | Finds disabled Cross-Site Request Forgery (CSRF) protection in Spring. Results are shown on LGTM by default. |
| Failure to use HTTPS or SFTP URL in Maven artifact upload/download (`java/maven/non-https-url`) | security, external/cwe/cwe-300, external/cwe/cwe-319, external/cwe/cwe-494, external/cwe/cwe-829 | Finds use of insecure protocols during Maven dependency resolution. Results are shown on LGTM by default. |
| LDAP query built from user-controlled sources (`java/ldap-injection`) | security, external/cwe/cwe-090 | Finds LDAP queries vulnerable to injection of unsanitized user-controlled input. Results are shown on LGTM by default. |
| Left shift by more than the type width (`java/lshift-larger-than-type-width`) | correctness | Finds left shifts of ints by 32 bits or more and left shifts of longs by 64 bits or more. Results are shown on LGTM by default. |
| Suspicious date format (`java/suspicious-date-format`) | correctness | Finds date format patterns that use placeholders that are likely to be incorrect. Results are shown on LGTM by default. |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
| 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.
* 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
looks for the occurrence of actual unit-test annotations. This affects the
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 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.

View File

@@ -1,100 +0,0 @@
# Improvements to JavaScript analysis
## General improvements
* TypeScript 3.8 is now supported.
* 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.
* 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.
* Call graph construction has been improved, leading to more results from the security queries:
- Calls can now be resolved to indirectly-defined class members in more cases.
- Calls through partial invocations such as `.bind` can now be resolved in more cases.
* Support for 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:
- [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. |
| 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. |
| 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. |
## Changes to existing queries
| **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 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. |
| 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. |
| 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. |
| 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
* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
* 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.

View File

@@ -1,55 +0,0 @@
# Improvements to Python analysis
The following changes in version 1.24 affect Python analysis in all applications.
## General improvements
- Support for Django version 2.x and 3.x
- 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.
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| 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 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`
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`
## Changes to libraries
### Taint tracking
- The `urlsplit` and `urlparse` functions now propagate taint appropriately.
- HTTP requests using the `requests` library are now modeled.

View File

@@ -1,7 +0,0 @@
[[ condition: enterprise-only ]]
# Improvements to JavaScript analysis
## Changes to code extraction
* `import.meta` expressions no longer result in a syntax error in JavaScript files.

View File

@@ -39,12 +39,6 @@
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C# Consistency checks": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll"
],
"C++ SubBasicBlocks": [
"cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll"
@@ -88,14 +82,6 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll"
],
"IR IRConfiguration": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll"
],
"IR UseSoundEscapeAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll"
],
"IR Operand Tag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll"
@@ -157,11 +143,6 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll"
],
"IR SSASanity": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll"
],
"C++ IR InstructionImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll",
@@ -196,14 +177,9 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll"
],
"SSA AliasAnalysis": [
"C++ SSA AliasAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll"
],
"C++ SSA AliasAnalysisImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysisImports.qll"
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll"
],
"C++ IR ValueNumberingImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
@@ -214,10 +190,6 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll"
],
"IR AliasConfiguration (unaliased_ssa)": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll"
],
"IR SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll",
@@ -228,27 +200,13 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
],
"IR ValueNumberInternal": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll"
],
"C++ IR ValueNumber": [
"IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll"
],
"C++ IR PrintValueNumbering": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll"
],
"C++ IR ConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll",
@@ -302,12 +260,5 @@
"C# IR ValueNumberingImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
],
"XML": [
"cpp/ql/src/semmle/code/cpp/XML.qll",
"csharp/ql/src/semmle/code/csharp/XML.qll",
"java/ql/src/semmle/code/xml/XML.qll",
"javascript/ql/src/semmle/javascript/XML.qll",
"python/ql/src/semmle/python/xml/XML.qll"
]
}

View File

@@ -1,140 +0,0 @@
#!/usr/bin/env python3
# Due to various technical limitations, we sometimes have files that need to be
# kept identical in the repository. This script loads a database of such
# files and can perform two functions: check whether they are still identical,
# and overwrite the others with a master copy if needed.
import hashlib
import shutil
import os
import sys
import json
import re
path = os.path
file_groups = {}
def add_prefix(prefix, relative):
result = path.join(prefix, relative)
if path.commonprefix((path.realpath(result), path.realpath(prefix))) != \
path.realpath(prefix):
raise Exception("Path {} is not below {}".format(
result, prefix))
return result
def load_if_exists(prefix, json_file_relative):
json_file_name = path.join(prefix, json_file_relative)
if path.isfile(json_file_name):
print("Loading file groups from", json_file_name)
with open(json_file_name, 'r', encoding='utf-8') as fp:
raw_groups = json.load(fp)
prefixed_groups = {
name: [
add_prefix(prefix, relative)
for relative in relatives
]
for name, relatives in raw_groups.items()
}
file_groups.update(prefixed_groups)
# Generates a list of C# test files that should be in sync
def csharp_test_files():
test_file_re = re.compile('.*(Bad|Good)[0-9]*\\.cs$')
csharp_doc_files = {
file:os.path.join(root, file)
for root, dirs, files in os.walk("csharp/ql/src")
for file in files
if test_file_re.match(file)
}
return {
"C# test '" + file + "'" : [os.path.join(root, file), csharp_doc_files[file]]
for root, dirs, files in os.walk("csharp/ql/test")
for file in files
if file in csharp_doc_files
}
def file_checksum(filename):
with open(filename, 'rb') as file_handle:
return hashlib.sha1(file_handle.read()).hexdigest()
def check_group(group_name, files, master_file_picker, emit_error):
checksums = {file_checksum(f) for f in files}
if len(checksums) == 1:
return
master_file = master_file_picker(files)
if master_file is None:
emit_error(__file__, 0,
"Files from group '"+ group_name +"' not in sync.")
emit_error(__file__, 0,
"Run this script with a file-name argument among the "
"following to overwrite the remaining files with the contents "
"of that file or run with the --latest switch to update each "
"group of files from the most recently modified file in the group.")
for filename in files:
emit_error(__file__, 0, " " + filename)
else:
print(" Syncing others from", master_file)
for filename in files:
if filename == master_file:
continue
print(" " + filename)
os.replace(filename, filename + '~')
shutil.copy(master_file, filename)
print(" Backups written with '~' appended to file names")
def chdir_repo_root():
root_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
os.chdir(root_path)
def choose_master_file(master_file, files):
if master_file in files:
return master_file
else:
return None
def choose_latest_file(files):
latest_time = None
latest_file = None
for filename in files:
file_time = os.path.getmtime(filename)
if (latest_time is None) or (latest_time < file_time):
latest_time = file_time
latest_file = filename
return latest_file
local_error_count = 0
def emit_local_error(path, line, error):
print('ERROR: ' + path + ':' + line + " - " + error)
global local_error_count
local_error_count += 1
# This function is invoked directly by a CI script, which passes a different error-handling
# callback.
def sync_identical_files(emit_error):
if len(sys.argv) == 1:
master_file_picker = lambda files: None
elif len(sys.argv) == 2:
if sys.argv[1] == "--latest":
master_file_picker = choose_latest_file
elif os.path.isfile(sys.argv[1]):
master_file_picker = lambda files: choose_master_file(sys.argv[1], files)
else:
raise Exception("File not found")
else:
raise Exception("Bad command line or file not found")
chdir_repo_root()
load_if_exists('.', 'config/identical-files.json')
file_groups.update(csharp_test_files())
for group_name, files in file_groups.items():
check_group(group_name, files, master_file_picker, emit_error)
def main():
sync_identical_files(emit_local_error)
if local_error_count > 0:
exit(1)
if __name__ == "__main__":
main()

View File

@@ -18,7 +18,6 @@
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors

View File

@@ -19,7 +19,6 @@
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors

View File

@@ -10,25 +10,12 @@ import cpp
/**
* An alert suppression comment.
*/
class SuppressionComment extends Comment {
class SuppressionComment extends CppStyleComment {
string annotation;
string text;
SuppressionComment() {
(
this instanceof CppStyleComment and
// strip the beginning slashes
text = getContents().suffix(2)
or
this instanceof CStyleComment and
// strip both the beginning /* and the end */ the comment
exists(string text0 |
text0 = getContents().suffix(2) and
text = text0.prefix(text0.length() - 2)
) and
// The /* */ comment must be a single-line comment
not text.matches("%\n%")
) and
text = getContents().suffix(2) and
(
// match `lgtm[...]` anywhere in the comment
annotation = text.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)

View File

@@ -3,7 +3,7 @@
* @description A function that uses more functions and variables from another file than functions and variables from its own file. This function might be better placed in the other file, to avoid exposing internals of the file it depends on.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @precision high
* @id cpp/feature-envy
* @tags maintainability
* modularity
@@ -25,8 +25,7 @@ predicate functionUsesFunction(Function source, Function f, File target) {
}
predicate dependencyCount(Function source, File target, int res) {
res =
strictcount(Declaration d |
res = strictcount(Declaration d |
functionUsesVariable(source, d, target) or
functionUsesFunction(source, d, target)
)

View File

@@ -38,16 +38,14 @@ where
n = count(Function f | f.fromSource()).toString()
or
l = "Number of Lines Of Code" and
n =
sum(File f, int toSum |
n = sum(File f, int toSum |
f.fromSource() and toSum = f.getMetrics().getNumberOfLinesOfCode()
|
toSum
).toString()
or
l = "Self-Containedness" and
n =
(
n = (
100 * sum(Class c | c.fromSource() | c.getMetrics().getEfferentSourceCoupling()) /
sum(Class c | c.fromSource() | c.getMetrics().getEfferentCoupling())
).toString() + "%"

View File

@@ -3,7 +3,7 @@
* @description Two files share too much information about each other (accessing many operations or variables in both directions). It would be better to invert some of the dependencies to reduce the coupling between the two files.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @precision high
* @id cpp/file-intimacy
* @tags maintainability
* modularity

View File

@@ -3,7 +3,7 @@
* @description Finds classes with many fields; they could probably be refactored by breaking them down into smaller classes, and using composition.
* @kind problem
* @problem.severity recommendation
* @precision medium
* @precision high
* @id cpp/class-many-fields
* @tags maintainability
* statistical
@@ -80,8 +80,11 @@ class VariableDeclarationLine extends TVariableDeclarationInfo {
* (that is, the first is 0, the second is 1 and so on).
*/
private int getRank() {
line =
rank[result](VariableDeclarationLine vdl, int l | vdl = TVariableDeclarationLine(c, f, l) | l)
line = rank[result](VariableDeclarationLine vdl, int l |
vdl = TVariableDeclarationLine(c, f, l)
|
l
)
}
/**
@@ -130,8 +133,7 @@ class VariableDeclarationGroup extends VariableDeclarationLine {
* Gets the number of uniquely named `VariableDeclarationEntry`s in this group.
*/
int getCount() {
result =
count(VariableDeclarationLine l |
result = count(VariableDeclarationLine l |
l = getProximateNext*()
|
l.getAVDE().getVariable().getName()
@@ -164,8 +166,7 @@ class ExtClass extends Class {
from ExtClass c, int n, VariableDeclarationGroup vdg, string suffix
where
n =
strictcount(string fieldName |
n = strictcount(string fieldName |
exists(Field f |
f.getDeclaringType() = c and
fieldName = f.getName() and

View File

@@ -50,8 +50,7 @@ class BlockOrNonChild extends Element {
private int getNonContiguousStartRankIn(AffectedFile file) {
// When using `rank` with `order by`, the ranks may not be contiguous.
this =
rank[result](BlockOrNonChild boc, int startLine, int startCol |
this = rank[result](BlockOrNonChild boc, int startLine, int startCol |
boc.getLocation().hasLocationInfo(file.getAbsolutePath(), startLine, startCol, _, _)
|
boc order by startLine, startCol
@@ -59,15 +58,13 @@ class BlockOrNonChild extends Element {
}
int getStartRankIn(AffectedFile file) {
this.getNonContiguousStartRankIn(file) =
rank[result](int rnk |
this.getNonContiguousStartRankIn(file) = rank[result](int rnk |
exists(BlockOrNonChild boc | boc.getNonContiguousStartRankIn(file) = rnk)
)
}
int getNonContiguousEndRankIn(AffectedFile file) {
this =
rank[result](BlockOrNonChild boc, int endLine, int endCol |
this = rank[result](BlockOrNonChild boc, int endLine, int endCol |
boc.getLocation().hasLocationInfo(file.getAbsolutePath(), _, _, endLine, endCol)
|
boc order by endLine, endCol
@@ -82,8 +79,9 @@ predicate emptyBlockContainsNonchild(Block b) {
emptyBlock(_, b) and
exists(BlockOrNonChild c, AffectedFile file |
c.(BlockOrNonChild).getStartRankIn(file) = 1 + b.(BlockOrNonChild).getStartRankIn(file) and
c.(BlockOrNonChild).getNonContiguousEndRankIn(file) <
b.(BlockOrNonChild).getNonContiguousEndRankIn(file)
c.(BlockOrNonChild).getNonContiguousEndRankIn(file) < b
.(BlockOrNonChild)
.getNonContiguousEndRankIn(file)
)
}

View File

@@ -4,9 +4,8 @@
* @kind problem
* @problem.severity warning
* @id cpp/japanese-era/exact-era-date
* @precision low
* @tags maintainability
* reliability
* @precision medium
* @tags reliability
* japanese-era
*/

View File

@@ -307,8 +307,7 @@ predicate nonTrivialValue(string value, Literal literal) {
}
predicate valueOccurrenceCount(string value, int n) {
n =
strictcount(Location loc |
n = strictcount(Location loc |
exists(Literal lit | lit.getLocation() = loc | nonTrivialValue(value, lit)) and
// Exclude generated files (they do not have the same maintainability
// concerns as ordinary source files)
@@ -339,8 +338,7 @@ predicate check(Literal lit, string value, int n, File f) {
}
predicate checkWithFileCount(string value, int overallCount, int fileCount, File f) {
fileCount =
strictcount(Location loc |
fileCount = strictcount(Location loc |
exists(Literal lit | lit.getLocation() = loc | check(lit, value, overallCount, f))
)
}
@@ -366,8 +364,7 @@ predicate firstOccurrence(Literal lit, string value, int n) {
predicate magicConstant(Literal e, string msg) {
exists(string value, int n |
firstOccurrence(e, value, n) and
msg =
"Magic constant: literal '" + value + "' is repeated " + n.toString() +
msg = "Magic constant: literal '" + value + "' is repeated " + n.toString() +
" times and should be encapsulated in a constant."
)
}

View File

@@ -28,15 +28,13 @@ import cpp
// design question and carries has no safety risk.
predicate generatedCopyAssignment(CopyConstructor cc, string msg) {
cc.getDeclaringType().hasImplicitCopyAssignmentOperator() and
msg =
"No matching copy assignment operator in class " + cc.getDeclaringType().getName() +
msg = "No matching copy assignment operator in class " + cc.getDeclaringType().getName() +
". It is good practice to match a copy constructor with a " + "copy assignment operator."
}
predicate generatedCopyConstructor(CopyAssignmentOperator ca, string msg) {
ca.getDeclaringType().hasImplicitCopyConstructor() and
msg =
"No matching copy constructor in class " + ca.getDeclaringType().getName() +
msg = "No matching copy constructor in class " + ca.getDeclaringType().getName() +
". It is good practice to match a copy assignment operator with a " + "copy constructor."
}

View File

@@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) {
)
}
predicate choice(StackVariable v, Stmt branch, string value) {
predicate choice(LocalScopeVariable v, Stmt branch, string value) {
exists(AnalysedExpr e |
testAndBranch(e, branch) and
(
@@ -33,7 +33,7 @@ predicate choice(StackVariable v, Stmt branch, string value) {
)
}
predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) {
predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) {
choice(v, loopstart, _) and
loopstart.getChildStmt*() = child.getEnclosingStmt() and
(definition(v, child) or exists(child.getNullSuccessor(v)))
@@ -47,7 +47,9 @@ predicate addressLeak(Variable v, Stmt leak) {
)
}
from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult
from
LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test,
string testresult
where
choice(v, branch, context) and
forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) |

View File

@@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) {
)
}
predicate openDefinition(StackVariable v, ControlFlowNode def) {
predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
}
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor())
exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
or
exists(StackVariable v, ControlFlowNode mid |
exists(LocalScopeVariable v, ControlFlowNode mid |
openDefinition(v, def) and
openReaches(def, mid) and
not errorSuccessor(v, mid) and
@@ -40,7 +40,7 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
)
}
predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
exists(Variable external |
assign.getRValue() = v.getAnAccess() and
assign.getLValue().(VariableAccess).getTarget() = external and
@@ -48,7 +48,7 @@ predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
)
}
from StackVariable v, ControlFlowNode def, ReturnStmt ret
from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
where
openDefinition(v, def) and
openReaches(def, ret) and

View File

@@ -6,7 +6,7 @@
<overview>
<p>
This rule finds calls to <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
This rule finds calls to <code>open</code> or <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
</p>
@@ -14,7 +14,7 @@ Leaving descriptors open will cause a resource leak that will persist even after
</overview>
<recommendation>
<p>Ensure that all socket descriptors allocated by the program are freed before it terminates.</p>
<p>Ensure that all file or socket descriptors allocated by the program are freed before it terminates.</p>
</recommendation>
<example>

View File

@@ -1,6 +1,6 @@
/**
* @name Open descriptor never closed
* @description Functions that always return before closing the socket they opened leak resources.
* @description Functions that always return before closing the socket or file they opened leak resources.
* @kind problem
* @id cpp/descriptor-never-closed
* @problem.severity warning

View File

@@ -10,7 +10,7 @@
*/
import FileClosed
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
/**
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
@@ -68,18 +68,18 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
)
}
predicate fopenDefinition(StackVariable v, ControlFlowNode def) {
predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
}
class FOpenVariableReachability extends StackVariableReachabilityWithReassignment {
class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
FOpenVariableReachability() { this = "FOpenVariableReachability" }
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
fopenDefinition(v, node)
}
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
// node may be used in fopenReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
fcloseCallOrIndirect(node, v) or
@@ -88,13 +88,15 @@ class FOpenVariableReachability extends StackVariableReachabilityWithReassignmen
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
definitionBarrier(v, node)
}
}
/**
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
*/
predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(FOpenVariableReachability r |
// reachability
r.reachesTo(def, _, node, v)
@@ -105,23 +107,25 @@ predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlow
)
}
class FOpenReachability extends StackVariableReachabilityExt {
class FOpenReachability extends LocalScopeVariableReachabilityExt {
FOpenReachability() { this = "FOpenReachability" }
override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) }
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
fopenDefinition(v, node)
}
override predicate isSink(ControlFlowNode node, StackVariable v) {
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the file (stored in any variable `v0`) opened at `source` is closed or
// assigned to a global at node, or NULL checked on the edge node -> next.
exists(StackVariable v0 | fopenVariableReaches(v0, source, node) |
exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
node.(AnalysedExpr).getNullSuccessor(v0) = next or
fcloseCallOrIndirect(node, v0) or
assignedToFieldOrGlobal(v0, node)
@@ -138,11 +142,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
exists(FOpenReachability r | r.reaches(def, _, node))
}
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
// assigned to anything except a StackVariable
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
@@ -159,7 +163,7 @@ predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
from ControlFlowNode def, ReturnStmt ret
where
fopenReaches(def, ret) and
not exists(StackVariable v |
not exists(LocalScopeVariable v |
fopenVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)

View File

@@ -11,7 +11,7 @@
import cpp
from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
checked = v.getAnAccess() and
dereferenced(checked) and

View File

@@ -13,7 +13,7 @@
import cpp
predicate negativeCheck(StackVariable v, ComparisonOperation op) {
predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
exists(int varindex, string constant, Literal lit |
op.getChild(varindex) = v.getAnAccess() and
op.getChild(1 - varindex) = lit and
@@ -38,7 +38,7 @@ predicate negativeCheck(StackVariable v, ComparisonOperation op) {
)
}
from StackVariable v, ArrayExpr dangerous, Expr check
from LocalScopeVariable v, ArrayExpr dangerous, Expr check
where
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
negativeCheck(v, check) and

View File

@@ -1,10 +1,17 @@
import semmle.code.cpp.pointsto.PointsTo
private predicate freed(Expr e) {
e = any(DeallocationExpr de).getFreedExpr()
exists(FunctionCall fc, Expr arg |
freeCall(fc, arg) and
arg = e
)
or
exists(DeleteExpr de | de.getExpr() = e)
or
exists(DeleteArrayExpr de | de.getExpr() = e)
or
exists(ExprCall c |
// cautiously assume that any `ExprCall` could be a deallocation expression.
// cautiously assume that any ExprCall could be a freeCall.
c.getAnArgument() = e
)
}
@@ -15,4 +22,7 @@ class FreedExpr extends PointsToExpr {
override predicate interesting() { freed(this) }
}
predicate allocMayBeFreed(AllocationExpr alloc) { anythingPointsTo(alloc) }
predicate allocMayBeFreed(Expr alloc) {
isAllocationExpr(alloc) and
anythingPointsTo(alloc)
}

View File

@@ -10,7 +10,7 @@
*/
import MemoryFreed
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
/**
* 'call' is either a direct call to f, or a possible call to f
@@ -24,7 +24,7 @@ predicate mayCallFunction(Expr call, Function f) {
predicate allocCallOrIndirect(Expr e) {
// direct alloc call
e.(AllocationExpr).requiresDealloc() and
isAllocationExpr(e) and
// We are only interested in alloc calls that are
// actually freed somehow, as MemoryNeverFreed
// will catch those that aren't.
@@ -53,7 +53,8 @@ predicate allocCallOrIndirect(Expr e) {
* can cause memory leaks.
*/
predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode verified) {
reallocCall.(AllocationExpr).getReallocPtr() = v.getAnAccess() and
reallocCall.getTarget().hasGlobalOrStdName("realloc") and
reallocCall.getArgument(0) = v.getAnAccess() and
(
exists(Variable newV, ControlFlowNode node |
// a realloc followed by a null check at 'node' (return the non-null
@@ -70,19 +71,23 @@ predicate verifiedRealloc(FunctionCall reallocCall, Variable v, ControlFlowNode
or
// a realloc(ptr, 0), which always succeeds and frees
// (return the realloc itself)
reallocCall.(AllocationExpr).getReallocPtr().getValue() = "0" and
reallocCall.getArgument(1).getValue() = "0" and
verified = reallocCall
)
}
predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
// direct free call
n.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
not exists(n.(AllocationExpr).getReallocPtr())
freeCall(n, v.getAnAccess()) and
not n.(FunctionCall).getTarget().hasGlobalOrStdName("realloc")
or
// verified realloc call
verifiedRealloc(_, v, n)
or
n.(DeleteExpr).getExpr() = v.getAnAccess()
or
n.(DeleteArrayExpr).getExpr() = v.getAnAccess()
or
exists(FunctionCall midcall, Function mid, int arg |
// indirect free call
n.(Call).getArgument(arg) = v.getAnAccess() and
@@ -92,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
)
}
predicate allocationDefinition(StackVariable v, ControlFlowNode def) {
predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
}
class AllocVariableReachability extends StackVariableReachabilityWithReassignment {
class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
AllocVariableReachability() { this = "AllocVariableReachability" }
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
allocationDefinition(v, node)
}
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
// node may be used in allocationReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
freeCallOrIndirect(node, v) or
@@ -112,13 +117,15 @@ class AllocVariableReachability extends StackVariableReachabilityWithReassignmen
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
definitionBarrier(v, node)
}
}
/**
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
*/
predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(AllocVariableReachability r |
// reachability
r.reachesTo(def, _, node, v)
@@ -129,25 +136,25 @@ predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, Control
)
}
class AllocReachability extends StackVariableReachabilityExt {
class AllocReachability extends LocalScopeVariableReachabilityExt {
AllocReachability() { this = "AllocReachability" }
override predicate isSource(ControlFlowNode node, StackVariable v) {
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
allocationDefinition(v, node)
}
override predicate isSink(ControlFlowNode node, StackVariable v) {
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the memory (stored in any variable `v0`) allocated at `source` is freed or
// assigned to a global at node, or NULL checked on the edge node -> next.
exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) |
exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
node.(AnalysedExpr).getNullSuccessor(v0) = next or
freeCallOrIndirect(node, v0) or
assignedToFieldOrGlobal(v0, node)
@@ -164,11 +171,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
exists(AllocReachability r | r.reaches(def, _, node))
}
predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
// assigned to anything except a StackVariable
predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
// assigned to anything except a LocalScopeVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
@@ -185,7 +192,7 @@ predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
from ControlFlowNode def, ReturnStmt ret
where
allocationReaches(def, ret) and
not exists(StackVariable v |
not exists(LocalScopeVariable v |
allocatedVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)

View File

@@ -11,8 +11,6 @@
import MemoryFreed
from AllocationExpr alloc
where
alloc.requiresDealloc() and
not allocMayBeFreed(alloc)
from Expr alloc
where isAllocationExpr(alloc) and not allocMayBeFreed(alloc)
select alloc, "This memory is never freed"

View File

@@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function {
predicate dangerousUse(IntegralReturnValue val, Expr use) {
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
or
exists(StackVariable v, ControlFlowNode def, ArrayExpr ae |
exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
exprDefinition(v, def, val) and
use = ae.getArrayOffset() and
not boundsChecked(v, use) and
@@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) {
val = use and
use.getType().getUnderlyingType() instanceof PointerType
or
exists(StackVariable v, ControlFlowNode def, AddExpr add |
exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
exprDefinition(v, def, val) and
definitionUsePair(v, def, use) and
add.getAnOperand() = use and

View File

@@ -5,34 +5,16 @@
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
(
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"
)
)
alloc instanceof FunctionCall and
kind = "malloc"
or
alloc instanceof NewExpr and
kind = "new" and
@@ -45,8 +27,7 @@ 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(_)
)
}
/**
@@ -79,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
pragma[nomagic]
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
exists(Expr mid |
not v instanceof StackVariable and
not v instanceof LocalScopeVariable and
v.getAnAssignedValue() = mid and
allocReaches0(mid, alloc, kind)
)
@@ -95,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
allocExprOrIndirect(alloc, kind) and
e = alloc
or
exists(SsaDefinition def, StackVariable v |
exists(SsaDefinition def, LocalScopeVariable v |
// alloc via SSA
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
e = def.getAUse(v)
@@ -128,20 +109,8 @@ predicate allocReaches(Expr e, Expr alloc, string kind) {
* describing the type of that free or delete.
*/
predicate freeExpr(Expr free, Expr freed, string kind) {
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"
)
)
freeCall(free, freed) and
kind = "free"
or
free.(DeleteExpr).getExpr() = freed and
kind = "delete"

View File

@@ -11,16 +11,26 @@
*/
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.models.interfaces.Allocation
class MallocCall extends FunctionCall {
MallocCall() { this.getTarget().hasGlobalOrStdName("malloc") }
Expr getAllocatedSize() {
if this.getArgument(0) instanceof VariableAccess
then
exists(LocalScopeVariable v, ControlFlowNode def |
definitionUsePair(v, def, this.getArgument(0)) and
exprDefinition(v, def, result)
)
else result = this.getArgument(0)
}
}
predicate spaceProblem(FunctionCall append, string msg) {
exists(
AllocationExpr malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer
|
exists(MallocCall malloc, StrlenCall strlen, AddExpr add, FunctionCall insert, Variable buffer |
add.getAChild() = strlen and
exists(add.getAChild().getValue()) and
DataFlow::localExprFlow(add, malloc.getSizeExpr()) and
malloc.getAllocatedSize() = add and
buffer.getAnAccess() = strlen.getStringExpr() and
(
insert.getTarget().hasGlobalOrStdName("strcpy") or
@@ -33,8 +43,7 @@ predicate spaceProblem(FunctionCall append, string msg) {
malloc.getASuccessor+() = insert and
insert.getArgument(1) = buffer.getAnAccess() and
insert.getASuccessor+() = append and
msg =
"This buffer only contains enough room for '" + buffer.getName() + "' (copied on line " +
msg = "This buffer only contains enough room for '" + buffer.getName() + "' (copied on line " +
insert.getLocation().getStartLine().toString() + ")"
)
}

View File

@@ -51,8 +51,7 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
loop.getStmt().getAChild*() = bufaccess.getEnclosingStmt() and
loop.limit() >= bufaccess.bufferSize() and
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
msg =
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
msg = "Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
bufaccess.bufferSize().toString() + " elements."
)
@@ -107,9 +106,8 @@ predicate wrongBufferSize(Expr error, string msg) {
statedSize = min(call.statedSizeValue()) and
statedSize > bufsize and
error = call.statedSizeExpr() and
msg =
"Potential buffer-overflow: '" + buf.getName() + "' has size " + bufsize.toString() + " not " +
statedSize + "."
msg = "Potential buffer-overflow: '" + buf.getName() + "' has size " + bufsize.toString() +
" not " + statedSize + "."
)
}
@@ -123,9 +121,8 @@ predicate outOfBounds(BufferAccess bufaccess, string msg) {
or
access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand())
) and
msg =
"Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf + "[" +
access.toString() + "]' is accessed here."
msg = "Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf +
"[" + access.toString() + "]' is accessed here."
)
}

View File

@@ -20,10 +20,11 @@ class ReturnPointsToExpr extends PointsToExpr {
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
}
from ReturnPointsToExpr ret, StackVariable local, float confidence
from ReturnPointsToExpr ret, LocalVariable local, float confidence
where
ret.pointsTo() = local and
ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and
not local.isStatic() and
confidence = ret.confidence() and
confidence > 0.01
select ret,

View File

@@ -23,8 +23,7 @@ predicate important(Function f, string message) {
predicate dubious(Function f, string message) {
not important(f, _) and
exists(Options opts, int used, int total, int percentage |
used =
count(FunctionCall fc |
used = count(FunctionCall fc |
fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc) and not unused(fc)
) and
total = count(FunctionCall fc | fc.getTarget() = f and not opts.okToIgnoreReturnValue(fc)) and

View File

@@ -20,10 +20,11 @@ class ScopeUtilityClass extends Class {
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
}
from StackVariable v, ControlFlowNode def
from LocalScopeVariable v, ControlFlowNode def
where
definition(v, def) and
not definitionUsePair(v, def, _) and
not v.isStatic() and
not v.getAnAccess().isAddressOfAccess() and
// parameter initializers are not in the call-graph at the moment
not v.(Parameter).getInitializer().getExpr() = def and

View File

@@ -10,10 +10,10 @@
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
/** `e` is an expression that frees the memory pointed to by `v`. */
predicate isFreeExpr(Expr e, StackVariable v) {
predicate isFreeExpr(Expr e, LocalScopeVariable v) {
exists(VariableAccess va | va.getTarget() = v |
exists(FunctionCall fc | fc = e |
fc.getTarget().hasGlobalOrStdName("free") and
@@ -27,7 +27,7 @@ predicate isFreeExpr(Expr e, StackVariable v) {
}
/** `e` is an expression that (may) dereference `v`. */
predicate isDerefExpr(Expr e, StackVariable v) {
predicate isDerefExpr(Expr e, LocalScopeVariable v) {
v.getAnAccess() = e and dereferenced(e)
or
isDerefByCallExpr(_, _, e, v)
@@ -39,27 +39,27 @@ predicate isDerefExpr(Expr e, StackVariable v) {
* or a source code function that dereferences the relevant
* parameter.
*/
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
v.getAnAccess() = va and
va = c.getAnArgumentSubExpr(i) and
not c.passesByReference(i, va) and
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
}
class UseAfterFreeReachability extends StackVariableReachability {
class UseAfterFreeReachability extends LocalScopeVariableReachability {
UseAfterFreeReachability() { this = "UseAfterFree" }
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
definitionBarrier(v, node) or
isFreeExpr(node, v)
}
}
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"

View File

@@ -18,13 +18,14 @@ string getCommentTextCaptioned(Comment c, string caption) {
dontCare = commentBody.regexpFind("\\n[/* \\t\\x0B\\f\\r]*" + caption, _, offset) and
interestingSuffix = commentBody.suffix(offset) and
endOfLine = interestingSuffix.indexOf("\n", 1, 0) and
captionedLine =
interestingSuffix
captionedLine = interestingSuffix
.prefix(endOfLine)
.regexpReplaceAll("^[/*\\s]*" + caption + "\\s*:?", "")
.trim() and
followingLine =
interestingSuffix.prefix(interestingSuffix.indexOf("\n", 2, 0)).suffix(endOfLine).trim() and
followingLine = interestingSuffix
.prefix(interestingSuffix.indexOf("\n", 2, 0))
.suffix(endOfLine)
.trim() and
if captionedLine = ""
then result = caption + " comment"
else

View File

@@ -56,8 +56,7 @@ VariableAccess getAnIncrement(Variable var) {
exists(AssignAddExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() =
any(AddExpr ae |
a.getRValue() = any(AddExpr ae |
ae.getAnOperand() = var.getAnAccess() and
ae.getAnOperand().getValue().toInt() > 0
)
@@ -73,8 +72,7 @@ VariableAccess getADecrement(Variable var) {
exists(AssignSubExpr a | a.getLValue() = result and a.getRValue().getValue().toInt() > 0)
or
exists(AssignExpr a | a.getLValue() = result |
a.getRValue() =
any(SubExpr ae |
a.getRValue() = any(SubExpr ae |
ae.getLeftOperand() = var.getAnAccess() and
ae.getRightOperand().getValue().toInt() > 0
)
@@ -130,16 +128,14 @@ where
exists(VariableAccess bound |
upperBoundCheck(loop, bound) and
reachesNoInc(bound, bound) and
msg =
"The loop counter " + bound.getTarget().getName() +
msg = "The loop counter " + bound.getTarget().getName() +
" is not always incremented in the loop body."
)
or
exists(VariableAccess bound |
lowerBoundCheck(loop, bound) and
reachesNoDec(bound, bound) and
msg =
"The loop counter " + bound.getTarget().getName() +
msg = "The loop counter " + bound.getTarget().getName() +
" is not always decremented in the loop body."
)
)

View File

@@ -21,7 +21,6 @@ where
if call.getTarget() = call.getEnclosingFunction()
then msg = "This call directly invokes its containing function $@."
else
msg =
"The function " + call.getEnclosingFunction() +
msg = "The function " + call.getEnclosingFunction() +
" is indirectly recursive via this call to $@."
select call, msg, call.getTarget(), call.getTarget().getName()

View File

@@ -17,8 +17,7 @@ predicate lockOrder(LockOperation outer, LockOperation inner) {
}
int orderCount(Declaration outerLock, Declaration innerLock) {
result =
strictcount(LockOperation outer, LockOperation inner |
result = strictcount(LockOperation outer, LockOperation inner |
outer.getLocked() = outerLock and
inner.getLocked() = innerLock and
lockOrder(outer, inner)
@@ -28,6 +27,6 @@ int orderCount(Declaration outerLock, Declaration innerLock) {
from LockOperation outer, LockOperation inner
where
lockOrder(outer, inner) and
orderCount(outer.getLocked(), inner.getLocked()) <=
orderCount(inner.getLocked(), outer.getLocked())
orderCount(outer.getLocked(), inner.getLocked()) <= orderCount(inner.getLocked(),
outer.getLocked())
select inner, "Out-of-order locks: A " + inner.say() + " usually precedes a $@.", outer, outer.say()

View File

@@ -81,8 +81,10 @@ class LockingPrimitive extends FunctionCall, LockOperation {
override Function getLocked() { result = this.getTarget() }
override UnlockOperation getMatchingUnlock() {
result.(UnlockingPrimitive).getTarget().getName() =
this.getTarget().getName().replaceAll("Lock", "Unlock")
result.(UnlockingPrimitive).getTarget().getName() = this
.getTarget()
.getName()
.replaceAll("Lock", "Unlock")
}
override string say() { result = "call to " + getLocked().getName() }

View File

@@ -29,8 +29,7 @@ where
numStmt(f, line) = cnt and
cnt > 1 and
o.onLine(f, line) and
o.getLocation().getStartColumn() =
min(OneLineStmt other, int toMin |
o.getLocation().getStartColumn() = min(OneLineStmt other, int toMin |
other.onLine(f, line) and toMin = other.getLocation().getStartColumn()
|
toMin

View File

@@ -14,8 +14,7 @@ import cpp
string var(Variable v) {
exists(int level | level = v.getType().getPointerIndirectionLevel() |
level > 2 and
result =
"The type of " + v.getName() + " uses " + level +
result = "The type of " + v.getName() + " uses " + level +
" levels of pointer indirection -- maximum allowed is 2."
)
}
@@ -23,8 +22,7 @@ string var(Variable v) {
string fun(Function f) {
exists(int level | level = f.getType().getPointerIndirectionLevel() |
level > 2 and
result =
"The return type of " + f.getName() + " uses " + level +
result = "The return type of " + f.getName() + " uses " + level +
" levels of pointer indirection -- maximum allowed is 2."
)
}

View File

@@ -12,8 +12,7 @@
import cpp
int firstCodeLine(File f) {
result =
min(Declaration d, Location l, int toMin |
result = min(Declaration d, Location l, int toMin |
(
l = d.getLocation() and
l.getFile() = f and

View File

@@ -18,8 +18,6 @@
import cpp
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
/**
* Holds if `e` is either:
@@ -59,122 +57,13 @@ Expr getMulOperand(MulExpr me) { result = me.getAnOperand() }
* ```
*/
int getEffectiveMulOperands(MulExpr me) {
result =
count(Expr op |
result = count(Expr op |
op = getMulOperand*(me) and
not op instanceof MulExpr and
not likelySmall(op)
)
}
/**
* As SimpleRangeAnalysis does not support reasoning about multiplication
* we create a tiny abstract interpreter for handling multiplication, which
* we invoke only after weeding out of all of trivial cases that we do
* not care about. By default, the maximum and minimum values are computed
* using SimpleRangeAnalysis.
*/
class AnalyzableExpr extends Expr {
float maxValue() { result = upperBound(this.getFullyConverted()) }
float minValue() { result = lowerBound(this.getFullyConverted()) }
}
class ParenAnalyzableExpr extends AnalyzableExpr, ParenthesisExpr {
override float maxValue() { result = this.getExpr().(AnalyzableExpr).maxValue() }
override float minValue() { result = this.getExpr().(AnalyzableExpr).minValue() }
}
class MulAnalyzableExpr extends AnalyzableExpr, MulExpr {
override float maxValue() {
exists(float x1, float y1, float x2, float y2 |
x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and
x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and
y2 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
result = (x1 * y1).maximum(x1 * y2).maximum(x2 * y1).maximum(x2 * y2)
)
}
override float minValue() {
exists(float x1, float x2, float y1, float y2 |
x1 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() and
x2 = this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
y1 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue() and
y2 = this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue() and
result = (x1 * y1).minimum(x1 * y2).minimum(x2 * y1).minimum(x2 * y2)
)
}
}
class AddAnalyzableExpr extends AnalyzableExpr, AddExpr {
override float maxValue() {
result =
this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() +
this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue()
}
override float minValue() {
result =
this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() +
this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue()
}
}
class SubAnalyzableExpr extends AnalyzableExpr, SubExpr {
override float maxValue() {
result =
this.getLeftOperand().getFullyConverted().(AnalyzableExpr).maxValue() -
this.getRightOperand().getFullyConverted().(AnalyzableExpr).minValue()
}
override float minValue() {
result =
this.getLeftOperand().getFullyConverted().(AnalyzableExpr).minValue() -
this.getRightOperand().getFullyConverted().(AnalyzableExpr).maxValue()
}
}
class VarAnalyzableExpr extends AnalyzableExpr, VariableAccess {
VarAnalyzableExpr() { this.getTarget() instanceof StackVariable }
override float maxValue() {
exists(SsaDefinition def, Variable v |
def.getAUse(v) = this and
// if there is a defining expression, use that for
// computing the maximum value. Otherwise, assign the
// variable the largest possible value it can hold
if exists(def.getDefiningValue(v))
then result = def.getDefiningValue(v).(AnalyzableExpr).maxValue()
else result = upperBound(this)
)
}
override float minValue() {
exists(SsaDefinition def, Variable v |
def.getAUse(v) = this and
if exists(def.getDefiningValue(v))
then result = def.getDefiningValue(v).(AnalyzableExpr).minValue()
else result = lowerBound(this)
)
}
}
/**
* Holds if `t` is not an instance of `IntegralType`,
* or if `me` cannot be proven to not overflow
*/
predicate overflows(MulExpr me, Type t) {
t instanceof IntegralType
implies
(
me.(MulAnalyzableExpr).maxValue() > exprMaxVal(me)
or
me.(MulAnalyzableExpr).minValue() < exprMinVal(me)
)
}
from MulExpr me, Type t1, Type t2
where
t1 = me.getType().getUnderlyingType() and
@@ -212,11 +101,7 @@ where
e = other.(BinaryOperation).getAnOperand*()
) and
e.(Literal).getType().getSize() = t2.getSize()
) and
// only report if we cannot prove that the result of the
// multiplication will be less (resp. greater) than the
// maximum (resp. minimum) number we can compute.
overflows(me, t1)
)
select me,
"Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '"
+ me.getFullyConverted().getType().toString() + "'."

View File

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

View File

@@ -52,7 +52,10 @@ predicate introducesNewField(Class derived, Class base) {
from DataFlow::PathNode source, DataFlow::PathNode sink, CastToPointerArithFlow cfg
where
cfg.hasFlowPath(source, sink) and
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() = sink
.getNode()
.asExpr()
.getFullyConverted()
.getUnspecifiedType()
select sink, source, sink,
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"

View File

@@ -37,7 +37,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
pathMightOverflow = false and
source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength()
or
exists(RangeSsaDefinition def, StackVariable v |
exists(RangeSsaDefinition def, LocalScopeVariable v |
flowsToDef(source, def, v, pathMightOverflow) and
sink = def.getAUse(v)
)
@@ -63,7 +63,9 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
* `pathMightOverflow` is true if there is an arithmetic operation
* on the path that might overflow.
*/
predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow) {
predicate flowsToDef(
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
) {
// Might the current definition overflow?
exists(boolean otherMightOverflow | flowsToDefImpl(source, def, v, otherMightOverflow) |
if defMightOverflow(def, v)
@@ -84,7 +86,7 @@ predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boole
* the path. But it is a good way to reduce the number of false positives.
*/
predicate flowsToDefImpl(
Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow
Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
) {
// Assignment or initialization: `e = v;`
exists(Expr e |

View File

@@ -130,8 +130,11 @@ predicate trivialConversion(ExpectedType expected, Type actual) {
or
// allow a pointer to any integral type of the same size
// (this permits signedness changes)
expected.(PointerType).getBaseType().(IntegralType).getSize() =
actual.(PointerType).getBaseType().(IntegralType).getSize()
expected.(PointerType).getBaseType().(IntegralType).getSize() = actual
.(PointerType)
.getBaseType()
.(IntegralType)
.getSize()
or
expected = actual
)

View File

@@ -25,16 +25,10 @@ predicate assertInvocation(File f, int line) {
)
}
class InterestingExpr extends Expr {
InterestingExpr() { nullCheckInCondition(this, _, _) }
}
predicate nullCheckAssert(InterestingExpr e, Variable v, Declaration qualifier) {
predicate nullCheckAssert(Expr e, Variable v, Declaration qualifier) {
nullCheckInCondition(e, v, qualifier) and
exists(File f, int i |
e.getLocation().getStartLine() = i and
e.getFile() = f and
assertInvocation(f, i) and
nullCheckInCondition(e, v, qualifier)
e.getLocation().getStartLine() = i and e.getFile() = f and assertInvocation(f, i)
)
}

View File

@@ -8,7 +8,6 @@
* @id cpp/leap-year/adding-365-days-per-year
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -6,7 +6,6 @@
* @id cpp/leap-year/unchecked-after-arithmetic-year-modification
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -8,7 +8,6 @@
* @id cpp/leap-year/unchecked-return-value-for-time-conversion-function
* @precision medium
* @tags leap-year
* correctness
*/
import cpp

View File

@@ -5,7 +5,7 @@
* @kind problem
* @problem.severity warning
* @id cpp/leap-year/unsafe-array-for-days-of-the-year
* @precision low
* @precision medium
* @tags security
* leap-year
*/

View File

@@ -12,24 +12,24 @@
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
class UndefReachability extends StackVariableReachability {
class UndefReachability extends LocalScopeVariableReachability {
UndefReachability() { this = "UndefReachability" }
override predicate isSource(ControlFlowNode node, StackVariable v) {
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
candidateVariable(v) and
node = v.getParentScope() and
not v instanceof Parameter and
not v.hasInitializer()
}
override predicate isSink(ControlFlowNode node, StackVariable v) {
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
candidateVariable(v) and
node = v.getAnAccess()
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
node.(AssignExpr).getLValue() = v.getAnAccess()
}
}
@@ -38,12 +38,6 @@ abstract class BooleanControllingAssignment extends AssignExpr {
abstract predicate isWhitelisted();
}
/**
* Gets an operand of a logical operation expression (we need the restriction
* to BinaryLogicalOperation expressions to get the correct transitive closure).
*/
Expr getComparisonOperand(BinaryLogicalOperation op) { result = op.getAnOperand() }
class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
BooleanControllingAssignmentInExpr() {
this.getParent() instanceof UnaryLogicalOperation or
@@ -51,18 +45,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
exists(ConditionalExpr c | c.getCondition() = this)
}
override predicate isWhitelisted() {
this.getConversion().(ParenthesisExpr).isParenthesised()
or
// whitelist this assignment if all comparison operations in the expression that this
// assignment is part of, are not parenthesized. In that case it seems like programmer
// is fine with unparenthesized comparison operands to binary logical operators, and
// the parenthesis around this assignment was used to call it out as an assignment.
this.isParenthesised() and
forex(ComparisonOperation op | op = getComparisonOperand*(this.getParent+()) |
not op.isParenthesised()
)
}
override predicate isWhitelisted() { this.getConversion().(ParenthesisExpr).isParenthesised() }
}
class BooleanControllingAssignmentInStmt extends BooleanControllingAssignment {
@@ -82,8 +65,7 @@ class BooleanControllingAssignmentInStmt extends BooleanControllingAssignment {
*/
predicate candidateResult(BooleanControllingAssignment ae) {
ae.getRValue().isConstant() and
not ae.isWhitelisted() and
not ae.getRValue() instanceof StringLiteral
not ae.isWhitelisted()
}
/**
@@ -99,6 +81,5 @@ predicate candidateVariable(Variable v) {
from BooleanControllingAssignment ae, UndefReachability undef
where
candidateResult(ae) and
not ae.isFromUninstantiatedTemplate(_) and
not undef.reaches(_, ae.getLValue().(VariableAccess).getTarget(), ae.getLValue())
select ae, "Use of '=' where '==' may have been intended."

View File

@@ -15,10 +15,7 @@ import cpp
from ExprInVoidContext op
where
not op.isUnevaluated() and
(
op instanceof EQExpr
or
op.(FunctionCall).getTarget().hasName("operator==")
)
op instanceof EQExpr
or
op.(FunctionCall).getTarget().hasName("operator==")
select op, "This '==' operator has no effect. The assignment ('=') operator was probably intended."

View File

@@ -65,8 +65,11 @@ predicate functionDefinedInIfDefRecursive(Function f) {
* break encapsulation.
*/
predicate baseCall(FunctionCall call) {
call.getNameQualifier().getQualifyingElement() =
call.getEnclosingFunction().getDeclaringType().(Class).getABaseClass+()
call.getNameQualifier().getQualifyingElement() = call
.getEnclosingFunction()
.getDeclaringType()
.(Class)
.getABaseClass+()
}
from PureExprInVoidContext peivc, Locatable parent, Locatable info, string info_text, string tail
@@ -81,10 +84,8 @@ where
not peivc.getEnclosingFunction().isDefaulted() and
not exists(Macro m | peivc = m.getAnInvocation().getAnExpandedElement()) and
not peivc.isFromTemplateInstantiation(_) and
not peivc.isFromUninstantiatedTemplate(_) and
parent = peivc.getParent() and
not parent.isInMacroExpansion() and
not peivc.isUnevaluated() and
not parent instanceof PureExprInVoidContext and
not peivc.getEnclosingFunction().isCompilerGenerated() and
not peivc.getType() instanceof UnknownType and

View File

@@ -35,8 +35,7 @@ predicate booleanLiteral(Literal l) {
string boolLiteralInLogicalOp(Literal literal) {
booleanLiteral(literal) and
literal.getParent() instanceof BinaryLogicalOperation and
result =
"Literal value " + literal.getValueText() +
result = "Literal value " + literal.getValueText() +
" is used in a logical expression; simplify or use a constant."
}

View File

@@ -40,8 +40,7 @@ where
l = v.log2().floor() and
if v = 2.pow(l)
then
msg =
"Operand to short-circuiting operator looks like a flag (" + v + " = 2 ^ " + l +
msg = "Operand to short-circuiting operator looks like a flag (" + v + " = 2 ^ " + l +
"), may be typo for bitwise operator."
else
exists(string kind |
@@ -50,8 +49,7 @@ where
or
e instanceof OctalLiteral and kind = "an octal literal"
) and
msg =
"Operand to short-circuiting operator is " + kind +
msg = "Operand to short-circuiting operator is " + kind +
", and therefore likely a flag; a bitwise operator may be intended."
)
select e, msg

View File

@@ -63,8 +63,7 @@ predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr
func = ce.getCondition()
)
) and
msg =
"Return value of " + func.getTarget().getName() +
msg = "Return value of " + func.getTarget().getName() +
" used directly in a conditional expression."
)
}

View File

@@ -111,20 +111,17 @@ predicate illDefinedForStmt(ForStmt for, string message) {
illDefinedForStmtWrongDirection(for, v, initialCondition, terminalCondition, isIncr) and
if for.conditionAlwaysFalse()
then
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is always false."
else
if for.conditionAlwaysTrue()
then
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is always true."
else
message =
"Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts " +
forLoopdirection(isIncr) + " from a value (" + initialCondition +
"), but the terminal condition is " + forLoopTerminalConditionRelationship(isIncr) +
" (" + terminalCondition + ")."

View File

@@ -11,7 +11,7 @@
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
import semmle.code.cpp.commons.NullTermination
/**
@@ -22,10 +22,10 @@ DeclStmt declWithNoInit(LocalVariable v) {
not exists(v.getInitializer())
}
class ImproperNullTerminationReachability extends StackVariableReachabilityWithReassignment {
class ImproperNullTerminationReachability extends LocalScopeVariableReachabilityWithReassignment {
ImproperNullTerminationReachability() { this = "ImproperNullTerminationReachability" }
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
node = declWithNoInit(v)
or
exists(Call c, VariableAccess va |
@@ -36,12 +36,12 @@ class ImproperNullTerminationReachability extends StackVariableReachabilityWithR
)
}
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
node.(VariableAccess).getTarget() = v and
variableMustBeNullTerminated(node)
}
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
exprDefinition(v, node, _) or
mayAddNullTerminator(node, v.getAnAccess()) or
isSinkActual(node, v) // only report first use

View File

@@ -122,7 +122,7 @@ class MallocSizeExpr extends BufferAccess, FunctionCall {
override Expr getPointer() { none() }
override Expr getAccessedLength() { result = getArgument(0) }
override Expr getAccessedLength() { result = getArgument(1) }
}
class NetworkFunctionCall extends FunctionCall {

View File

@@ -30,9 +30,9 @@ class SprintfCall extends FunctionCall {
predicate isDangerous() { this.getMaxConvertedLength() > this.getBufferSize() }
string getDescription() {
result =
"This conversion may yield a string of length " + this.getMaxConvertedLength().toString() +
", which exceeds the allocated buffer size of " + this.getBufferSize().toString()
result = "This conversion may yield a string of length " +
this.getMaxConvertedLength().toString() + ", which exceeds the allocated buffer size of " +
this.getBufferSize().toString()
}
}

View File

@@ -42,8 +42,10 @@ predicate hasNontrivialConversion(Expr e) {
hasNontrivialConversion(e.getConversion())
}
from StackVariable var, VariableAccess va, ReturnStmt r
from LocalScopeVariable var, VariableAccess va, ReturnStmt r
where
not var.isStatic() and
not var.isThreadLocal() and
not var.getUnspecifiedType() instanceof ReferenceType and
not r.isFromUninstantiatedTemplate(_) and
va = var.getAnAccess() and

View File

@@ -12,7 +12,7 @@
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.controlflow.LocalScopeVariableReachability
/**
* Auxiliary predicate: Types that don't require initialization
@@ -40,17 +40,23 @@ DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
not allocatedType(v.getType())
not allocatedType(v.getType()) and
/* The variable is not static (otherwise it is zeroed). */
not v.isStatic() and
/* The variable is not extern (otherwise it is zeroed). */
not v.hasSpecifier("extern")
}
class UninitialisedLocalReachability extends StackVariableReachability {
class UninitialisedLocalReachability extends LocalScopeVariableReachability {
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
node = declWithNoInit(v)
}
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVarActual(v, node) }
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
// only report the _first_ possibly uninitialized use
useOfVarActual(v, node) or
definitionBarrier(v, node)

View File

@@ -3,20 +3,9 @@
"qhelp.dtd">
<qhelp>
<overview>
<p>Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols may expose the software to known vulnerabilities or permit weak encryption algorithms to be used. Disabling the minimum-recommended protocols is also flagged.</p>
<p>Using TLS or SSLv23 protool from the boost::asio library, but not disabling deprecated protocols or disabling minimum-recommended protocols.</p>
</overview>
<recommendation>
<p>When using the TLS or SSLv23 protocol, set the <code>no_tlsv1</code> and <code>no_tlsv1_1</code> options, but do not set <code>no_tlsv1_2</code>. When using the SSLv23 protocol, also set the <code>no_sslv3</code> option.</p>
</recommendation>
<example>
<p>In the following example, the <code>no_tlsv1_1</code> option has not been set. Use of TLS 1.1 is not recommended.</p>
<sample src="TlsSettingsMisconfigurationBad.cpp"/>
<p>In the corrected example, the <code>no_tlsv1</code> and <code>no_tlsv1_1</code> options have both been set, ensuring the use of TLS 1.2 or later.</p>
<sample src="TlsSettingsMisconfigurationGood.cpp"/>
</example>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.

View File

@@ -1,9 +1,9 @@
/**
* @name Boost_asio TLS Settings Misconfiguration
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
* @description Using TLS or SSLv23 protool 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
*/

View File

@@ -1,8 +0,0 @@
void useTLS_bad()
{
boost::asio::ssl::context ctx(boost::asio::ssl::context::tls);
ctx.set_options(boost::asio::ssl::context::no_tlsv1); // BAD: missing no_tlsv1_1
// ...
}

View File

@@ -1,8 +0,0 @@
void useTLS_good()
{
boost::asio::ssl::context ctx(boost::asio::ssl::context::tls);
ctx.set_options(boost::asio::ssl::context::no_tlsv1 | boost::asio::ssl::context::no_tlsv1_1); // GOOD
// ...
}

View File

@@ -4,22 +4,13 @@
<qhelp>
<overview>
<p>Using boost::asio library but specifying a deprecated hardcoded protocol.</p>
<p>Using a deprecated hardcoded protocol instead of negotiting would lock your application to a protocol that has known vulnerabilities or weaknesses.</p>
</overview>
<recommendation>
<p>Only use modern protocols such as TLS 1.2 or TLS 1.3.</p>
</recommendation>
<example>
<p>In the following example, the <code>sslv2</code> protocol is specified. This protocol is out of date and its use is not recommended.</p>
<sample src="UseOfDeprecatedHardcodedProtocolBad.cpp"/>
<p>In the corrected example, the <code>tlsv13</code> protocol is used instead.</p>
<sample src="UseOfDeprecatedHardcodedProtocolGood.cpp"/>
</example>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.
</li>
</references>
</qhelp>

View File

@@ -1,7 +0,0 @@
void useProtocol_bad()
{
boost::asio::ssl::context ctx_sslv2(boost::asio::ssl::context::sslv2); // BAD: outdated protocol
// ...
}

View File

@@ -1,7 +0,0 @@
void useProtocol_good()
{
boost::asio::ssl::context cxt_tlsv13(boost::asio::ssl::context::tlsv13);
// ...
}

View File

@@ -28,8 +28,7 @@ class NullInstruction extends ConstantValueInstruction {
}
predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool =
any(CompareInstruction cmp |
bool = any(CompareInstruction cmp |
exists(NullInstruction null |
cmp.getLeft() = null and cmp.getRight() = checked
or
@@ -41,8 +40,7 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
)
)
or
bool =
any(ConvertInstruction convert |
bool = any(ConvertInstruction convert |
checked = convert.getUnary() and
convert.getResultType() instanceof BoolType and
checked.getResultType() instanceof PointerType

View File

@@ -8,6 +8,6 @@ struct S {
// Whereas here it does make a semantic difference.
auto getValCorrect() const -> int {
return val;
return val
}
};

View File

@@ -17,9 +17,7 @@ where
hasSuperfluousConstReturn(f) and
if f.hasSpecifier("const") or f.isStatic()
then
message =
"The 'const' modifier has no effect on return types. The 'const' modifying the return type can be removed."
message = "The 'const' modifier has no effect on return types. The 'const' modifying the return type can be removed."
else
message =
"The 'const' modifier has no effect on return types. For a const function, the 'const' should go after the parameter list."
message = "The 'const' modifier has no effect on return types. For a const function, the 'const' should go after the parameter list."
select f, message

View File

@@ -1,8 +0,0 @@
/* '#include <stdlib.h>' was forgotton */
int main(void) {
/* 'int malloc()' assumed */
unsigned char *p = malloc(100);
*p = 'a';
return 0;
}

View File

@@ -1,29 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>A function is called without a prior function declaration or definition.
When this happens, the compiler generates an implicit declaration of the function,
specifying an integer return type and no parameters.
If the implicit declaration does not match the true signature of the function, the
function may behave unpredictably.</p>
<p>This may indicate a misspelled function name, or that the required header containing
the function declaration has not been included.</p>
</overview>
<recommendation>
<p>Provide an explicit declaration of the function before invoking it.</p>
</recommendation>
<example><sample src="ImplicitFunctionDeclaration.c" />
</example>
<references>
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL31-C.+Declare+identifiers+before+using+them">DCL31-C. Declare identifiers before using them</a></li>
</references>
</qhelp>

View File

@@ -1,48 +0,0 @@
/**
* @name Implicit function declaration
* @description An implicitly declared function is assumed to take no
* arguments and return an integer. If this assumption does not hold, it
* may lead to unpredictable behavior.
* @kind problem
* @problem.severity warning
* @precision high
* @id cpp/implicit-function-declaration
* @tags correctness
* maintainability
*/
import cpp
import MistypedFunctionArguments
import TooFewArguments
import TooManyArguments
import semmle.code.cpp.commons.Exclusions
predicate locInfo(Locatable e, File file, int line, int col) {
e.getFile() = file and
e.getLocation().getStartLine() = line and
e.getLocation().getStartColumn() = col
}
predicate sameLocation(FunctionDeclarationEntry fde, FunctionCall fc) {
exists(File file, int line, int col |
locInfo(fde, file, line, col) and
locInfo(fc, file, line, col)
)
}
predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
from FunctionDeclarationEntry fdeIm, FunctionCall fc
where
isCompiledAsC(fdeIm.getFile()) and
not isFromMacroDefinition(fc) and
fdeIm.isImplicit() and
sameLocation(fdeIm, fc) and
not mistypedFunctionArguments(fc, _, _) and
not tooFewArguments(fc, _) and
not tooManyArguments(fc, _)
select fc, "Function call implicitly declares '" + fdeIm.getName() + "'."

View File

@@ -12,10 +12,95 @@
*/
import cpp
import MistypedFunctionArguments
predicate arithTypesMatch(Type arg, Type parm) {
arg = parm
or
arg.getSize() = parm.getSize() and
(
arg instanceof IntegralOrEnumType and
parm instanceof IntegralOrEnumType
or
arg instanceof FloatingPointType and
parm instanceof FloatingPointType
)
}
pragma[inline]
predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// conversion to/from pointers to void is allowed
arg instanceof VoidType
or
parm instanceof VoidType
}
pragma[inline]
predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
nestedPointerArgTypeMayBeUsed(arg, parm)
or
// nested pointers
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
}
pragma[inline]
predicate argTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// pointers to compatible types
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
// C11 arrays
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
}
// This predicate holds whenever expression `arg` may be used to initialize
// function parameter `parm` without need for run-time conversion.
pragma[inline]
predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
from FunctionCall fc, Function f, Parameter p
where mistypedFunctionArguments(fc, f, p)
where
f = fc.getTarget() and
p = f.getAParameter() and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
not f.isVarargs() and
not f instanceof BuiltInFunction and
p.getIndex() < fc.getNumberOfArguments() and
// Parameter p and its corresponding call argument must have mismatched types
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(),
fc.getArgument(p.getIndex()) as arg, arg.toString(),
arg.getExplicitlyConverted().getUnspecifiedType() as atype, atype.toString(), p, p.getTypedName()

View File

@@ -1,97 +0,0 @@
/**
* Provides the implementation of the MistypedFunctionArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
pragma[inline]
private predicate arithTypesMatch(Type arg, Type parm) {
arg = parm
or
arg.getSize() = parm.getSize() and
(
arg instanceof IntegralOrEnumType and
parm instanceof IntegralOrEnumType
or
arg instanceof FloatingPointType and
parm instanceof FloatingPointType
)
}
pragma[inline]
private predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// conversion to/from pointers to void is allowed
arg instanceof VoidType
or
parm instanceof VoidType
}
pragma[inline]
private predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
nestedPointerArgTypeMayBeUsed(arg, parm)
or
// nested pointers
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
}
pragma[inline]
private predicate argTypeMayBeUsed(Type arg, Type parm) {
// arithmetic types
arithTypesMatch(arg, parm)
or
// pointers to compatible types
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(PointerType).getBaseType().getUnspecifiedType())
or
// C11 arrays
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
or
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
parm.(ArrayType).getBaseType().getUnspecifiedType())
}
// This predicate holds whenever expression `arg` may be used to initialize
// function parameter `parm` without need for run-time conversion.
pragma[inline]
private predicate argMayBeUsed(Expr arg, Parameter parm) {
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
}
// True if function was ()-declared, but not (void)-declared or K&R-defined
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
f = fc.getTarget() and
p = f.getAParameter() and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
not f.isVarargs() and
not f instanceof BuiltInFunction and
p.getIndex() < fc.getNumberOfArguments() and
// Parameter p and its corresponding call argument must have mismatched types
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
}

View File

@@ -15,8 +15,31 @@
*/
import cpp
import TooFewArguments
// True if function was ()-declared, but not (void)-declared or K&R-defined
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
from FunctionCall fc, Function f
where tooFewArguments(fc, f)
where
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
select fc, "This call has fewer arguments than required by $@.", f, f.toString()

View File

@@ -1,34 +0,0 @@
/**
* Provides the implementation of the TooFewArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate tooFewArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
}

View File

@@ -12,8 +12,35 @@
*/
import cpp
import TooManyArguments
// True if function was ()-declared, but not (void)-declared or K&R-defined
// or implicitly declared (i.e., lacking a prototype)
predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.isImplicit() and
not fde.hasVoidParamList() and
fde.getNumberOfParameters() = 0 and
not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
predicate isCompiledAsC(Function f) {
exists(File file | file.compiledAsC() |
file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
)
}
from FunctionCall fc, Function f
where tooManyArguments(fc, f)
where
f = fc.getTarget() and
not f.isVarargs() and
hasZeroParamDecl(f) and
isCompiledAsC(f) and
exists(f.getBlock()) and
// There must not exist a declaration with the number of parameters
// at least as large as the number of call arguments
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
)
select fc, "This call has more arguments than required by $@.", f, f.toString()

View File

@@ -1,38 +0,0 @@
/**
* Provides the implementation of the TooManyArguments query. The
* query is implemented as a library, so that we can avoid producing
* duplicate results in other similar queries.
*/
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
// or implicitly declared (i.e., lacking a prototype)
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.isImplicit() and
not fde.hasVoidParamList() and
fde.getNumberOfParameters() = 0 and
not fde.isDefinition()
)
}
// True if this file (or header) was compiled as a C file
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
predicate tooManyArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
exists(f.getBlock()) and
// There must not exist a declaration with the number of parameters
// at least as large as the number of call arguments
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
)
}

View File

@@ -14,7 +14,6 @@ import cpp
from Class c, int n
where
c.fromSource() and
n =
c.getMetrics().getNumberOfMembers() +
n = c.getMetrics().getNumberOfMembers() +
sum(Function f | c.getACanonicalMemberFunction() = f | f.getMetrics().getNumberOfLinesOfCode())
select c, n order by n desc

View File

@@ -15,15 +15,16 @@ import cpp
from Class c, int ccLoc, int loc
where
c.fromSource() and
ccLoc =
sum(Function f |
ccLoc = sum(Function f |
c.getACanonicalMemberFunction() = f and
f.getMetrics().getCyclomaticComplexity() > 18
|
f.getMetrics().getNumberOfLinesOfCode()
) and
loc =
sum(Function f | c.getACanonicalMemberFunction() = f | f.getMetrics().getNumberOfLinesOfCode()) +
c.getMetrics().getNumberOfMembers() and
loc = sum(Function f |
c.getACanonicalMemberFunction() = f
|
f.getMetrics().getNumberOfLinesOfCode()
) + c.getMetrics().getNumberOfMembers() and
loc != 0
select c, (ccLoc * 100).(float) / loc as n order by n desc

View File

@@ -76,8 +76,7 @@ class Library extends LibraryT {
* `sourceFile` is not in `destLib`).
*/
predicate libDependencies(File sourceFile, Library destLib, int num) {
num =
strictcount(Element source, Element dest, File destFile |
num = strictcount(Element source, Element dest, File destFile |
// dependency from source -> dest.
dependsOnSimple(source, dest) and
sourceFile = source.getFile() and
@@ -102,7 +101,7 @@ predicate libDependencies(File sourceFile, Library destLib, int num) {
predicate encodedDependencies(File source, string encodedDependency, int num) {
exists(Library destLib |
libDependencies(source, destLib, num) and
encodedDependency =
"/" + source.getRelativePath() + "<|>" + destLib.getName() + "<|>" + destLib.getVersion()
encodedDependency = "/" + source.getRelativePath() + "<|>" + destLib.getName() + "<|>" +
destLib.getVersion()
)
}

View File

@@ -85,8 +85,7 @@ private predicate closeWithDepth(int depth, File f, PreprocessorDirective close,
predicate length(PreprocessorDirective open, int length) {
exists(int depth, File f, int start, int end |
openWithDepth(depth, f, open, start) and
end =
min(PreprocessorDirective endif, int closeLine |
end = min(PreprocessorDirective endif, int closeLine |
closeWithDepth(depth, f, endif, closeLine) and
closeLine > start
|

View File

@@ -19,8 +19,7 @@ where
if loc > 0
then
// Weighted average of complexity by function length
complexity =
sum(FunctionDeclarationEntry fde |
complexity = sum(FunctionDeclarationEntry fde |
fde.getFile() = f
|
fde.getNumberOfLines() * fde.getCyclomaticComplexity()

View File

@@ -17,8 +17,7 @@ import external.CodeDuplication
from File f, int n
where
n =
count(int line |
n = count(int line |
exists(DuplicateBlock d | d.sourceFile() = f |
line in [d.sourceStartLine() .. d.sourceEndLine()]
) and

View File

@@ -15,8 +15,7 @@ import cpp
from File f, int n
where
f.fromSource() and
n =
count(Comment c |
n = count(Comment c |
c.getFile() = f and
(
c.getContents().matches("%TODO%") or

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