Compare commits

..

1 Commits

Author SHA1 Message Date
Tamás Vajk
5d994c9b08 Revert "C#: Extract relational patterns" 2020-11-27 12:44:07 +01:00
3836 changed files with 97070 additions and 294613 deletions

View File

@@ -1,23 +0,0 @@
name: Check change note
on:
pull_request_target:
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
paths:
- "*/ql/src/**/*.ql"
- "*/ql/src/**/*.qll"
- "!**/experimental/**"
jobs:
check-change-note:
runs-on: ubuntu-latest
steps:
- name: Fail if no change note found. To fix, either add one, or add the `no-change-note-required` label.
if: |
github.event.pull_request.draft == false &&
!contains(github.event.pull_request.labels.*.name, 'no-change-note-required')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate |
jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' --exit-status

View File

@@ -2,15 +2,7 @@ name: "Code scanning - action"
on:
push:
branches:
- main
- 'rc/*'
pull_request:
branches:
- main
- 'rc/*'
paths:
- 'csharp/**'
schedule:
- cron: '0 9 * * 1'
@@ -22,7 +14,16 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1

3
.gitignore vendored
View File

@@ -17,9 +17,6 @@
# Byte-compiled python files
*.pyc
# python virtual environment folder
.venv/
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
/codeql/

View File

@@ -1,3 +1,3 @@
{
"omnisharp.autoStart": false
}
}

View File

@@ -4,16 +4,17 @@
/javascript/ @github/codeql-javascript
/python/ @github/codeql-python
# Make @xcorail (GitHub Security Lab) a code owner for experimental queries so he gets pinged when we promote a query out of experimental
/cpp/**/experimental/**/* @github/codeql-c-analysis @xcorail
/csharp/**/experimental/**/* @github/codeql-csharp @xcorail
/java/**/experimental/**/* @github/codeql-java @xcorail
/javascript/**/experimental/**/* @github/codeql-javascript @xcorail
/python/**/experimental/**/* @github/codeql-python @xcorail
# Assign query help for docs review
/cpp/**/*.qhelp @hubwriter
/csharp/**/*.qhelp @jf205
/java/**/*.qhelp @felicitymay
/javascript/**/*.qhelp @mchammer01
/python/**/*.qhelp @felicitymay
/docs/language/ @shati-patel @jf205
# Notify members of codeql-go about PRs to the shared data-flow library files
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
# Exclude help for experimental queries from docs review
/cpp/**/experimental/**/*.qhelp @github/codeql-c-analysis
/csharp/**/experimental/**/*.qhelp @github/codeql-csharp
/java/**/experimental/**/*.qhelp @github/codeql-java
/javascript/**/experimental/**/*.qhelp @github/codeql-javascript
/python/**/experimental/**/*.qhelp @github/codeql-python

View File

@@ -38,8 +38,6 @@ If you have an idea for a query that you would like to share with other CodeQL u
- 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).
If you prefer, you can use this [pre-commit hook](misc/scripts/pre-commit) that automatically checks whether your files are correctly formatted. See the [pre-commit hook installation guide](docs/pre-commit-hook-setup.md) for instructions on how to install the hook.
4. **Compilation**
- 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`.
@@ -49,11 +47,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
- The query must have at least one true positive result on some revision of a real project.
6. **Query help files and unit tests**
- Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. For more information about contributing query help files and unit tests, see [Supported CodeQL queries and libraries](docs/supported-queries.md).
Experimental queries and libraries may not be actively maintained as the supported libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings.
Experimental queries and libraries may not be actively maintained as the [supported](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).

View File

@@ -70,3 +70,4 @@
## Changes to libraries
* The predicate `TypeAnnotation.hasQualifiedName` now works in more cases when the imported library was not present during extraction.
* The class `DomBasedXss::Configuration` has been deprecated, as it has been split into `DomBasedXss::HtmlInjectionConfiguration` and `DomBasedXss::JQueryHtmlOrSelectorInjectionConfiguration`. Unless specifically working with jQuery sinks, subclasses should instead be based on `HtmlInjectionConfiguration`. To use both configurations in a query, see [Xss.ql](https://github.com/github/codeql/blob/main/javascript/ql/src/Security/CWE-079/Xss.ql) for an example.

View File

@@ -4,34 +4,19 @@ The following changes in version 1.26 affect Python analysis in all applications
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
|`py/unsafe-deserialization` | Different results. | The underlying data flow library has been changed. See below for more details. |
|`py/path-injection` | Different results. | The underlying data flow library has been changed. See below for more details. |
|`py/command-line-injection` | Different results. | The underlying data flow library has been changed. See below for more details. |
|`py/reflective-xss` | Different results. | The underlying data flow library has been changed. See below for more details. |
|`py/sql-injection` | Different results. | The underlying data flow library has been changed. See below for more details. |
|`py/code-injection` | Different results. | The underlying data flow library has been changed. See below for more details. |
## Changes to libraries
* Some of the security queries now use the shared data flow library for data flow and taint tracking. This has resulted in an overall more robust and accurate analysis. The libraries mentioned below have been modelled in this new framework. Other libraries (e.g. the web framework `CherryPy`) have not been modelled yet, and this may lead to a temporary loss of results for these frameworks.
* Improved modelling of the following serialization libraries:
- `PyYAML`
- `dill`
- `pickle`
- `marshal`
* Improved modelling of the following web frameworks:
- `Django` (Note that modelling of class-based response handlers is currently incomplete.)
- `Flask`
* Support for Werkzeug `MultiDict`.
* Support for the [Python Database API Specification v2.0 (PEP-249)](https://www.python.org/dev/peps/pep-0249/), including the following libraries:
- `MySQLdb`
- `mysql-connector-python`
- `django.db`
* Improved modelling of the following command execution libraries:
- `Fabric`
- `Invoke`
* Improved modelling of security-related standard library modules, such as `os`, `popen2`, `platform`, and `base64`.
* The original versions of the updated queries have been preserved [here](https://github.com/github/codeql/tree/main/python/ql/src/experimental/Security-old-dataflow).
* Added taint tracking support for string formatting through f-strings.

View File

@@ -36,7 +36,6 @@
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
@@ -357,7 +356,6 @@
],
"Inline Test Expectations": [
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"
],
"C++ ExternalAPIs": [
@@ -375,49 +373,50 @@
"javascript/ql/src/semmle/javascript/XML.qll",
"python/ql/src/semmle/python/xml/XML.qll"
],
"DuplicationProblems.inc.qhelp": [
"cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
"javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp",
"python/ql/src/Metrics/DuplicationProblems.inc.qhelp"
"DuplicationProblems.qhelp": [
"cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
"csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
"javascript/ql/src/Metrics/DuplicationProblems.qhelp",
"python/ql/src/Metrics/DuplicationProblems.qhelp"
],
"CommentedOutCodeQuery.inc.qhelp": [
"cpp/ql/src/Documentation/CommentedOutCodeQuery.inc.qhelp",
"python/ql/src/Lexical/CommentedOutCodeQuery.inc.qhelp",
"csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.inc.qhelp",
"java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.inc.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeQuery.inc.qhelp"
"CommentedOutCodeQuery.qhelp": [
"cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp",
"python/ql/src/Lexical/CommentedOutCodeQuery.qhelp",
"csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp",
"java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeQuery.qhelp"
],
"FLinesOfCodeReferences.inc.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeReferences.inc.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeReferences.inc.qhelp"
"FLinesOfCodeReferences.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeReferences.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeReferences.qhelp"
],
"FCommentRatioCommon.inc.qhelp": [
"java/ql/src/Metrics/Files/FCommentRatioCommon.inc.qhelp",
"javascript/ql/src/Metrics/FCommentRatioCommon.inc.qhelp"
"FCommentRatioCommon.qhelp": [
"java/ql/src/Metrics/Files/FCommentRatioCommon.qhelp",
"javascript/ql/src/Metrics/FCommentRatioCommon.qhelp"
],
"FLinesOfCodeOverview.inc.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeOverview.inc.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeOverview.inc.qhelp"
"FLinesOfCodeOverview.qhelp": [
"java/ql/src/Metrics/Files/FLinesOfCodeOverview.qhelp",
"javascript/ql/src/Metrics/FLinesOfCodeOverview.qhelp"
],
"CommentedOutCodeMetricOverview.inc.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeMetricOverview.inc.qhelp",
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.inc.qhelp"
"CommentedOutCodeMetricOverview.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeMetricOverview.qhelp",
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.qhelp"
],
"FLinesOfDuplicatedCodeCommon.inc.qhelp": [
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp",
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp"
"FLinesOfDuplicatedCodeCommon.qhelp": [
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp",
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp"
],
"CommentedOutCodeReferences.inc.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeReferences.inc.qhelp",
"python/ql/src/Lexical/CommentedOutCodeReferences.inc.qhelp"
"CommentedOutCodeReferences.qhelp": [
"cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"java/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
"javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp",
"python/ql/src/Lexical/CommentedOutCodeReferences.qhelp"
],
"IDE Contextual Queries": [
"cpp/ql/src/IDEContextual.qll",
@@ -425,15 +424,5 @@
"java/ql/src/IDEContextual.qll",
"javascript/ql/src/IDEContextual.qll",
"python/ql/src/analysis/IDEContextual.qll"
],
"SSA C#": [
"csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
"csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll"
],
"CryptoAlgorithms Python/JS": [
"javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll",
"python/ql/src/semmle/crypto/Crypto.qll"
]
}
}

View File

@@ -5,7 +5,6 @@ using System;
using System.Linq;
using Microsoft.Build.Construction;
using System.Xml;
using System.IO;
namespace Semmle.Autobuild.Cpp.Tests
{
@@ -44,8 +43,6 @@ namespace Semmle.Autobuild.Cpp.Tests
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
public HashSet<string> CreateDirectories { get; } = new HashSet<string>();
public HashSet<(string, string)> DownloadFiles { get; } = new HashSet<(string, string)>();
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
{
@@ -138,14 +135,6 @@ namespace Semmle.Autobuild.Cpp.Tests
string IBuildActions.GetFullPath(string path) => path;
string? IBuildActions.GetFileName(string? path) => Path.GetFileName(path?.Replace('\\', '/'));
public string? GetDirectoryName(string? path)
{
var dir = Path.GetDirectoryName(path?.Replace('\\', '/'));
return dir is null ? path : path?.Substring(0, dir.Length);
}
void IBuildActions.WriteAllText(string filename, string contents)
{
}
@@ -164,18 +153,6 @@ namespace Semmle.Autobuild.Cpp.Tests
s = s.Replace($"%{kvp.Key}%", kvp.Value);
return s;
}
public void CreateDirectory(string path)
{
if (!CreateDirectories.Contains(path))
throw new ArgumentException($"Missing CreateDirectory, {path}");
}
public void DownloadFile(string address, string fileName)
{
if (!DownloadFiles.Contains((address, fileName)))
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
}
}
/// <summary>
@@ -236,7 +213,6 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64";
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
@@ -297,8 +273,7 @@ namespace Semmle.Autobuild.Cpp.Tests
[Fact]
public void TestCppAutobuilderSuccess()
{
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
@@ -311,13 +286,11 @@ namespace Semmle.Autobuild.Cpp.Tests
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
Actions.EnumerateDirectories[@"C:\Project"] = "";
Actions.CreateDirectories.Add(@"C:\Project\.nuget");
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe"));
var autobuilder = CreateAutoBuilder(true);
var solution = new TestSolution(@"C:\Project\test.sln");
autobuilder.ProjectsOrSolutionsToBuild.Add(solution);
TestAutobuilderScript(autobuilder, 0, 3);
TestAutobuilderScript(autobuilder, 0, 2);
}
}
}

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
<ApplicationIcon />
@@ -17,7 +17,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +0,0 @@
lgtm,codescanning
* `FormattingFunction.getOutputParameterIndex` now has a parameter identifying whether the output at that index is a buffer or a stream.
* `FormattingFunction` now has a predicate `isOutputGlobal` indicating when the output is to a global stream.
* The `primitiveVariadicFormatter` and `variadicFormatter` predicates have more parameters exposing information about the function.

View File

@@ -1,2 +0,0 @@
lgtm
* A new query (`cpp/unsigned-difference-expression-compared-zero`) is run but not yet displayed on LGTM. The query finds unsigned subtractions used in relational comparisons with the value 0. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4745.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* A new query (`cpp/memset-may-be-deleted`) is added to the default query suite. The query finds calls to `memset` that may be removed by the compiler. This behavior can make information-leak vulnerabilities easier to exploit. This query was originally [submitted as an experimental query by @ihsinme](https://github.com/github/codeql/pull/4953).

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly.

View File

@@ -1,2 +0,0 @@
codescanning
* Added cpp/diagnostics/failed-extractions. This query gives information about which extractions did not run to completion.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* The 'Resource not released in destructor' (cpp/resource-not-released-in-destructor) query has been improved to recognize more releases of resources.

View File

@@ -1,2 +0,0 @@
lgtm,codescanning
* The 'Assignment where comparison was intended' (cpp/assign-where-compare-meant) query has been improved to flag fewer benign assignments in conditionals.

View File

@@ -10,7 +10,6 @@
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions
+ semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions
+ semmlecode-cpp-queries/Likely Bugs/OO/UnsafeUseOfThis.ql: /Correctness/Dangerous Conversions
+ semmlecode-cpp-queries/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql: /Correctness/Dangerous Conversions
# Consistent Use
+ semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use
+ semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use

View File

@@ -4,6 +4,9 @@
* @kind graph
* @id cpp/architecture/class-hierarchies
* @graph.layout organic
* @workingset jhotdraw
* @result succeed 48
* @result_ondemand succeed 48
* @tags maintainability
*/

View File

@@ -4,6 +4,9 @@
* @kind chart
* @id cpp/architecture/inheritance-depth-distribution
* @chart.type line
* @workingset jhotdraw
* @result succeed 48
* @result_ondemand succeed 48
* @tags maintainability
*/

View File

@@ -1,8 +1,7 @@
/**
* @name Global namespace classes
* @description Finds classes that belong to no namespace.
* @kind problem
* @problem.severity recommendation
* @kind table
* @id cpp/architecture/global-namespace-classes
* @tags maintainability
* modularity

View File

@@ -4,6 +4,9 @@
* @kind problem
* @id cpp/architecture/classes-with-many-dependencies
* @problem.severity recommendation
* @workingset jhotdraw
* @result succeed 20
* @result_ondemand succeed 20
* @tags maintainability
* statistical
* non-attributable

View File

@@ -8,41 +8,168 @@ import semmle.code.cpp.AutogeneratedFile
predicate trivialPositiveIntValue(string s) {
// Small numbers
s = [0 .. 20].toString() or
s =
[
// Popular powers of two (decimal)
"16", "24", "32", "64", "128", "256", "512", "1024", "2048", "4096", "16384", "32768",
"65536", "1048576", "2147483648", "4294967296",
// Popular powers of two, minus one (decimal)
"15", "31", "63", "127", "255", "511", "1023", "2047", "4095", "16383", "32767", "65535",
"1048577", "2147483647", "4294967295",
// Popular powers of two (32-bit hex)
"0x00000001", "0x00000002", "0x00000004", "0x00000008", "0x00000010", "0x00000020",
"0x00000040", "0x00000080", "0x00000100", "0x00000200", "0x00000400", "0x00000800",
"0x00001000", "0x00002000", "0x00004000", "0x00008000", "0x00010000", "0x00020000",
"0x00040000", "0x00080000", "0x00100000", "0x00200000", "0x00400000", "0x00800000",
"0x01000000", "0x02000000", "0x04000000", "0x08000000", "0x10000000", "0x20000000",
"0x40000000", "0x80000000",
// Popular powers of two, minus one (32-bit hex)
"0x00000001", "0x00000003", "0x00000007", "0x0000000f", "0x0000001f", "0x0000003f",
"0x0000007f", "0x000000ff", "0x000001ff", "0x000003ff", "0x000007ff", "0x00000fff",
"0x00001fff", "0x00003fff", "0x00007fff", "0x0000ffff", "0x0001ffff", "0x0003ffff",
"0x0007ffff", "0x000fffff", "0x001fffff", "0x003fffff", "0x007fffff", "0x00ffffff",
"0x01ffffff", "0x03ffffff", "0x07ffffff", "0x0fffffff", "0x1fffffff", "0x3fffffff",
"0x7fffffff", "0xffffffff",
// Popular powers of two (16-bit hex)
"0x0001", "0x0002", "0x0004", "0x0008", "0x0010", "0x0020", "0x0040", "0x0080", "0x0100",
"0x0200", "0x0400", "0x0800", "0x1000", "0x2000", "0x4000", "0x8000",
// Popular powers of two, minus one (16-bit hex)
"0x0001", "0x0003", "0x0007", "0x000f", "0x001f", "0x003f", "0x007f", "0x00ff", "0x01ff",
"0x03ff", "0x07ff", "0x0fff", "0x1fff", "0x3fff", "0x7fff", "0xffff",
// Popular powers of two (8-bit hex)
"0x01", "0x02", "0x04", "0x08", "0x10", "0x20", "0x40", "0x80",
// Popular powers of two, minus one (8-bit hex)
"0x01", "0x03", "0x07", "0x0f", "0x1f", "0x3f", "0x7f", "0xff", "0x00",
// Powers of ten
"10", "100", "1000", "10000", "100000", "1000000", "10000000", "100000000", "1000000000"
]
// Popular powers of two (decimal)
s = "16" or
s = "24" or
s = "32" or
s = "64" or
s = "128" or
s = "256" or
s = "512" or
s = "1024" or
s = "2048" or
s = "4096" or
s = "16384" or
s = "32768" or
s = "65536" or
s = "1048576" or
s = "2147483648" or
s = "4294967296" or
// Popular powers of two, minus one (decimal)
s = "15" or
s = "31" or
s = "63" or
s = "127" or
s = "255" or
s = "511" or
s = "1023" or
s = "2047" or
s = "4095" or
s = "16383" or
s = "32767" or
s = "65535" or
s = "1048577" or
s = "2147483647" or
s = "4294967295" or
// Popular powers of two (32-bit hex)
s = "0x00000001" or
s = "0x00000002" or
s = "0x00000004" or
s = "0x00000008" or
s = "0x00000010" or
s = "0x00000020" or
s = "0x00000040" or
s = "0x00000080" or
s = "0x00000100" or
s = "0x00000200" or
s = "0x00000400" or
s = "0x00000800" or
s = "0x00001000" or
s = "0x00002000" or
s = "0x00004000" or
s = "0x00008000" or
s = "0x00010000" or
s = "0x00020000" or
s = "0x00040000" or
s = "0x00080000" or
s = "0x00100000" or
s = "0x00200000" or
s = "0x00400000" or
s = "0x00800000" or
s = "0x01000000" or
s = "0x02000000" or
s = "0x04000000" or
s = "0x08000000" or
s = "0x10000000" or
s = "0x20000000" or
s = "0x40000000" or
s = "0x80000000" or
// Popular powers of two, minus one (32-bit hex)
s = "0x00000001" or
s = "0x00000003" or
s = "0x00000007" or
s = "0x0000000f" or
s = "0x0000001f" or
s = "0x0000003f" or
s = "0x0000007f" or
s = "0x000000ff" or
s = "0x000001ff" or
s = "0x000003ff" or
s = "0x000007ff" or
s = "0x00000fff" or
s = "0x00001fff" or
s = "0x00003fff" or
s = "0x00007fff" or
s = "0x0000ffff" or
s = "0x0001ffff" or
s = "0x0003ffff" or
s = "0x0007ffff" or
s = "0x000fffff" or
s = "0x001fffff" or
s = "0x003fffff" or
s = "0x007fffff" or
s = "0x00ffffff" or
s = "0x01ffffff" or
s = "0x03ffffff" or
s = "0x07ffffff" or
s = "0x0fffffff" or
s = "0x1fffffff" or
s = "0x3fffffff" or
s = "0x7fffffff" or
s = "0xffffffff" or
// Popular powers of two (16-bit hex)
s = "0x0001" or
s = "0x0002" or
s = "0x0004" or
s = "0x0008" or
s = "0x0010" or
s = "0x0020" or
s = "0x0040" or
s = "0x0080" or
s = "0x0100" or
s = "0x0200" or
s = "0x0400" or
s = "0x0800" or
s = "0x1000" or
s = "0x2000" or
s = "0x4000" or
s = "0x8000" or
// Popular powers of two, minus one (16-bit hex)
s = "0x0001" or
s = "0x0003" or
s = "0x0007" or
s = "0x000f" or
s = "0x001f" or
s = "0x003f" or
s = "0x007f" or
s = "0x00ff" or
s = "0x01ff" or
s = "0x03ff" or
s = "0x07ff" or
s = "0x0fff" or
s = "0x1fff" or
s = "0x3fff" or
s = "0x7fff" or
s = "0xffff" or
// Popular powers of two (8-bit hex)
s = "0x01" or
s = "0x02" or
s = "0x04" or
s = "0x08" or
s = "0x10" or
s = "0x20" or
s = "0x40" or
s = "0x80" or
// Popular powers of two, minus one (8-bit hex)
s = "0x01" or
s = "0x03" or
s = "0x07" or
s = "0x0f" or
s = "0x1f" or
s = "0x3f" or
s = "0x7f" or
s = "0xff" or
s = "0x00" or
// Powers of ten
s = "10" or
s = "100" or
s = "1000" or
s = "10000" or
s = "100000" or
s = "1000000" or
s = "10000000" or
s = "100000000" or
s = "1000000000"
}
predicate trivialIntValue(string s) {
@@ -108,7 +235,10 @@ predicate joiningStringTrivial(Literal lit) {
// understand (which is against the spirit of these queries).
stringLiteral(lit) and
exists(FunctionCall fc |
fc.getTarget().getName() = ["operator+", "operator<<"] and
(
fc.getTarget().getName() = "operator+" or
fc.getTarget().getName() = "operator<<"
) and
fc.getAnArgument().getAChild*() = lit
) and
lit.getValue().length() < 16
@@ -161,7 +291,8 @@ predicate arrayInitializerChild(AggregateLiteral parent, Expr e) {
// i.e. not a constant folded expression
predicate literallyLiteral(Literal lit) {
lit.getValueText()
lit
.getValueText()
.regexpMatch(".*\".*|\\s*+[-+]?+\\s*+(0[xob][0-9a-fA-F]|[0-9])[0-9a-fA-F,._]*+([eE][-+]?+[0-9,._]*+)?+\\s*+[a-zA-Z]*+\\s*+")
}

View File

@@ -9,7 +9,7 @@
It is likely that these conditions indicate an error in the branching condition.
Alternatively, the conditions may have been left behind after debugging.</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -13,7 +13,7 @@ If left in the code base they increase object code size, decrease code comprehen
This type of function may be part of the program's API and could be used by external programs.
</p>
<include src="callGraphWarning.inc.qhelp" />
<include src="callGraphWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ This query looks at functions that return file or socket descriptors, but may re
This can occur when an operation performed on the open descriptor fails, and the function returns with an error before it closes the open resource. An improperly handled error could cause the function to leak resource descriptors. Failing to close resources in the function that opened them also makes it more difficult to detect leaks.
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ This rule finds calls to <code>socket</code> where there is no corresponding <co
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ This rule looks at functions that return a <code>FILE*</code>, but may return an
This can occur when an operation performed on the open descriptor fails, and the function returns with an error before closing the open resource. An improperly handled error may cause the function to leak file descriptors.
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ This rule finds calls to <code>fopen</code> with no corresponding <code>fclose</
Leaving files open will cause a resource leak that will persist even after the program terminates.
</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ Not all compilers generate code that zero-out memory, especially when optimizati
is not compliant with the latest language standards. Accessing uninitialized memory will lead to undefined results.
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -12,7 +12,7 @@ Dereferencing a null pointer and attempting to modify its contents can lead to a
important system data (including the interrupt table in some architectures).
</p>
<include src="pointsToWarning.inc.qhelp" />
<include src="pointsToWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -11,7 +11,7 @@ Uninitialized variables may contain any value, as not all compilers generate cod
optimizations are enabled or the compiler is not compliant with the latest language standards.
</p>
<include src="callGraphWarning.inc.qhelp" />
<include src="callGraphWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -13,7 +13,7 @@ after. Otherwise, if the value is negative then the program will have failed
before performing the test.
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -9,7 +9,7 @@
This rule looks for functions that allocate memory, but may return without freeing it. This can occur when an operation performed on the memory block fails, and the function returns with an error before freeing the allocated block. This causes the function to leak memory and may eventually lead to software failure.
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -10,7 +10,7 @@ This rule finds calls to the <code>alloc</code> family of functions without a co
This leads to memory leaks.
</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -16,7 +16,7 @@ buffer overruns.
The query looks only at the return values of functions that may return a negative value (not all functions).
</p>
<include src="dataFlowWarning.inc.qhelp" />
<include src="dataFlowWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -63,7 +63,7 @@ destructors likely not be called (as previously noted), but the pointer will als
potentially less of a serious issue than that posed by the first approach, but it should still be avoided.</li>
</ul>
<include src="pointsToWarning.inc.qhelp" />
<include src="pointsToWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -18,7 +18,7 @@ an array (which could have header data specifying the length of the array) and w
element of the 'array', which would likely lead to a segfault due to the invalid header data.
</p>
<include src="pointsToWarning.inc.qhelp" />
<include src="pointsToWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -19,7 +19,7 @@ the data being copied. Buffer overflows can result to anything from a segmentati
if the array is on stack-allocated memory).
</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -14,7 +14,7 @@ Buffer overflows can lead to anything from a segmentation fault to a security vu
Ensure that the size parameter is derived from the size of the destination buffer, and
not the source buffer.</p>
<include src="aliasAnalysisWarning.inc.qhelp" />
<include src="aliasAnalysisWarning.qhelp" />
</recommendation>

View File

@@ -12,7 +12,7 @@ the contents of that memory become undefined after that. Clearly, using a pointe
memory after the function has already returned will have undefined results.
</p>
<include src="pointsToWarning.inc.qhelp" />
<include src="pointsToWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -12,7 +12,7 @@ from a segfault to memory corruption that would cause subsequent calls to the dy
erratically, to a possible security vulnerability.
</p>
<include src="pointsToWarning.inc.qhelp" />
<include src="pointsToWarning.qhelp" />
</overview>
<recommendation>

View File

@@ -59,9 +59,14 @@ class Options extends string {
predicate exits(Function f) {
f.getAnAttribute().hasName("noreturn")
or
f.hasGlobalOrStdName([
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
])
exists(string name | f.hasGlobalOrStdName(name) |
name = "exit" or
name = "_exit" or
name = "abort" or
name = "__assert_fail" or
name = "longjmp" or
name = "__builtin_unreachable"
)
or
CustomOptions::exits(f) // old Options.qll
}

View File

@@ -1,16 +0,0 @@
/**
* @name Extraction errors
* @description List all extraction errors for files in the source code directory.
* @kind diagnostic
* @id cpp/diagnostics/extraction-errors
*/
import cpp
import ExtractionErrors
from ExtractionError error
where
error instanceof ExtractionUnknownError or
exists(error.getFile().getRelativePath())
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
error.getSeverity()

View File

@@ -1,137 +0,0 @@
/**
* Provides a common hierarchy of all types of errors that can occur during extraction.
*/
import cpp
/*
* A note about how the C/C++ extractor emits diagnostics:
* When the extractor frontend encounters an error, it emits a diagnostic message,
* that includes a message, location and severity.
* However, that process is best-effort and may fail (e.g. due to lack of memory).
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
* error (or higher), it *also* emits a simple "There was an error during this compilation"
* error diagnostic, without location information.
* In the common case, this means that a compilation during which one or more errors happened also gets
* the catch-all diagnostic.
* This diagnostic has the empty string as file path.
* We filter out these useless diagnostics if there is at least one error-level diagnostic
* for the affected compilation in the database.
* Otherwise, we show it to indicate that something went wrong and that we
* don't know what exactly happened.
*/
/**
* An error that, if present, leads to a file being marked as non-successfully extracted.
*/
class ReportableError extends Diagnostic {
ReportableError() {
(
this instanceof CompilerDiscretionaryError or
this instanceof CompilerError or
this instanceof CompilerCatastrophe
) and
// Filter for the catch-all diagnostic, see note above.
not this.getFile().getAbsolutePath() = ""
}
}
private newtype TExtractionError =
TReportableError(ReportableError err) or
TCompilationFailed(Compilation c, File f) {
f = c.getAFileCompiled() and not c.normalTermination()
} or
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
// for that compilation
TUnknownError(CompilerError err) {
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
}
/**
* Superclass for the extraction error hierarchy.
*/
class ExtractionError extends TExtractionError {
/** Gets the string representation of the error. */
string toString() { none() }
/** Gets the error message for this error. */
string getErrorMessage() { none() }
/** Gets the file this error occured in. */
File getFile() { none() }
/** Gets the location this error occured in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this error. */
int getSeverity() {
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
// so all errors have severity 2.
result = 2
}
}
/**
* An unrecoverable extraction error, where extraction was unable to finish.
* This can be caused by a multitude of reasons, for example:
* - hitting a frontend assertion
* - crashing due to dereferencing an invalid pointer
* - stack overflow
* - out of memory
*/
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
Compilation c;
File f;
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
override string toString() {
result = "Unrecoverable extraction error while compiling " + f.toString()
}
override string getErrorMessage() { result = "unrecoverable compilation failure." }
override File getFile() { result = f }
override Location getLocation() { result = f.getLocation() }
}
/**
* A recoverable extraction error.
* These are compiler errors from the frontend.
* Upon encountering one of these, we still continue extraction, but the
* database will be incomplete for that file.
*/
class ExtractionRecoverableError extends ExtractionError, TReportableError {
ReportableError err;
ExtractionRecoverableError() { this = TReportableError(err) }
override string toString() { result = "Recoverable extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}
/**
* An unknown error happened during extraction.
* These are only displayed if we know that we encountered an error during extraction,
* but, for some reason, failed to emit a proper diagnostic with location information
* and error message.
*/
class ExtractionUnknownError extends ExtractionError, TUnknownError {
CompilerError err;
ExtractionUnknownError() { this = TUnknownError(err) }
override string toString() { result = "Unknown extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}

View File

@@ -1,22 +0,0 @@
/**
* @name Failed extractor invocations
* @description Gives the command line of compilations for which extraction did not run to completion.
* @kind diagnostic
* @id cpp/diagnostics/failed-extractor-invocations
*/
import cpp
class AnonymousCompilation extends Compilation {
override string toString() { result = "<compilation>" }
}
string describe(Compilation c) {
if c.getArgument(1) = "--mimic"
then result = "compiler invocation " + concat(int i | i > 1 | c.getArgument(i), " " order by i)
else result = "extractor invocation " + concat(int i | | c.getArgument(i), " " order by i)
}
from Compilation c
where not c.normalTermination()
select c, "Extraction aborted for " + describe(c), 2

View File

@@ -1,15 +0,0 @@
/**
* @name Successfully extracted files
* @description Lists all files in the source code directory that were extracted without encountering an error in the file.
* @kind diagnostic
* @id cpp/diagnostics/successfully-extracted-files
*/
import cpp
import ExtractionErrors
from File f
where
not exists(ExtractionError e | e.getFile() = f) and
exists(f.getRelativePath())
select f, ""

View File

@@ -2,6 +2,6 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CommentedOutCodeQuery.inc.qhelp" />
<include src="../Metrics/Files/CommentedOutCodeReferences.inc.qhelp" />
<include src="CommentedOutCodeQuery.qhelp" />
<include src="../Metrics/Files/CommentedOutCodeReferences.qhelp" />
</qhelp>

View File

@@ -21,7 +21,15 @@ class Initialization extends Function {
}
class Allocation extends FunctionCall {
Allocation() { this.getTarget().getName() = ["malloc", "calloc", "alloca", "sbrk", "valloc"] }
Allocation() {
exists(string name | name = this.getTarget().getName() |
name = "malloc" or
name = "calloc" or
name = "alloca" or
name = "sbrk" or
name = "valloc"
)
}
}
from Function f, Allocation a

View File

@@ -13,8 +13,13 @@ import cpp
class ForbiddenCall extends FunctionCall {
ForbiddenCall() {
this.getTarget().getName() =
["task_delay", "taskDelay", "sleep", "nanosleep", "clock_nanosleep"]
exists(string name | name = this.getTarget().getName() |
name = "task_delay" or
name = "taskDelay" or
name = "sleep" or
name = "nanosleep" or
name = "clock_nanosleep"
)
}
}

View File

@@ -6,7 +6,12 @@ import cpp
class SemaphoreCreation extends FunctionCall {
SemaphoreCreation() {
this.getTarget().getName() = ["semBCreate", "semMCreate", "semCCreate", "semRWCreate"]
exists(string name | name = this.getTarget().getName() |
name = "semBCreate" or
name = "semMCreate" or
name = "semCCreate" or
name = "semRWCreate"
)
}
Variable getSemaphore() { result.getAnAccess() = this.getParent().(Assignment).getLValue() }
@@ -67,7 +72,11 @@ class SemaphoreGive extends UnlockOperation {
}
class LockingPrimitive extends FunctionCall, LockOperation {
LockingPrimitive() { this.getTarget().getName() = ["taskLock", "intLock", "taskRtpLock"] }
LockingPrimitive() {
exists(string name | name = this.getTarget().getName() |
name = "taskLock" or name = "intLock" or name = "taskRtpLock"
)
}
override Function getLocked() { result = this.getTarget() }
@@ -80,7 +89,11 @@ class LockingPrimitive extends FunctionCall, LockOperation {
}
class UnlockingPrimitive extends FunctionCall, UnlockOperation {
UnlockingPrimitive() { this.getTarget().getName() = ["taskUnlock", "intUnlock", "taskRtpUnlock"] }
UnlockingPrimitive() {
exists(string name | name = this.getTarget().getName() |
name = "taskUnlock" or name = "intUnlock" or name = "taskRtpUnlock"
)
}
Function getLocked() { result = getMatchingLock().getLocked() }

View File

@@ -12,7 +12,18 @@
import cpp
predicate allowedTypedefs(TypedefType t) {
t.getName() = ["I64", "U64", "I32", "U32", "I16", "U16", "I8", "U8", "F64", "F32"]
exists(string name | name = t.getName() |
name = "I64" or
name = "U64" or
name = "I32" or
name = "U32" or
name = "I16" or
name = "U16" or
name = "I8" or
name = "U8" or
name = "F64" or
name = "F32"
)
}
/**

View File

@@ -5,8 +5,8 @@ import cpp
*/
class Task extends Function {
Task() {
exists(FunctionCall taskCreate |
taskCreate.getTarget().getName() = ["taskCreate", "taskSpawn"] and
exists(FunctionCall taskCreate, string name | name = "taskCreate" or name = "taskSpawn" |
name = taskCreate.getTarget().getName() and
this = taskCreate.getArgument(4).(AddressOfExpr).getAddressable()
)
}

View File

@@ -13,17 +13,38 @@ import cpp
import semmle.code.cpp.dataflow.DataFlow
predicate whitelist(Function f) {
f.getName() =
[
"ceil", "ceilf", "ceill", "floor", "floorf", "floorl", "nearbyint", "nearbyintf",
"nearbyintl", "rint", "rintf", "rintl", "round", "roundf", "roundl", "trunc", "truncf",
"truncl"
] or
f.getName().matches("__builtin_%")
exists(string fName |
fName = f.getName() and
(
fName = "ceil" or
fName = "ceilf" or
fName = "ceill" or
fName = "floor" or
fName = "floorf" or
fName = "floorl" or
fName = "nearbyint" or
fName = "nearbyintf" or
fName = "nearbyintl" or
fName = "rint" or
fName = "rintf" or
fName = "rintl" or
fName = "round" or
fName = "roundf" or
fName = "roundl" or
fName = "trunc" or
fName = "truncf" or
fName = "truncl" or
fName.matches("__builtin_%")
)
)
}
predicate whitelistPow(FunctionCall fc) {
fc.getTarget().getName() = ["pow", "powf", "powl"] and
(
fc.getTarget().getName() = "pow" or
fc.getTarget().getName() = "powf" or
fc.getTarget().getName() = "powl"
) and
exists(float value |
value = fc.getArgument(0).getValue().toFloat() and
(value.floor() - value).abs() < 0.001

View File

@@ -3,7 +3,7 @@
"qhelp.dtd">
<qhelp>
<overview>
<include src="LeapYear.inc.qhelp" />
<include src="LeapYear.qhelp" />
<p>When performing arithmetic operations on a variable that represents a date, leap years must be taken into account.
It is not safe to assume that a year is 365 days long.</p>

View File

@@ -3,7 +3,7 @@
"qhelp.dtd">
<qhelp>
<overview>
<include src="LeapYear.inc.qhelp" />
<include src="LeapYear.qhelp" />
<p>When performing arithmetic operations on a variable that represents a year, it is important to consider that the resulting value may not be a valid date.</p>
<p>The typical example is doing simple year arithmetic (i.e. <code>date.year++</code>) without considering if the resulting value will be a valid date or not.</p>

View File

@@ -3,7 +3,7 @@
"qhelp.dtd">
<qhelp>
<overview>
<include src="LeapYear.inc.qhelp" />
<include src="LeapYear.qhelp" />
<p>When using a function that transforms a date structure, and the year on the input argument for the API has been manipulated, it is important to check for the return value of the function to make sure it succeeded.</p>
<p>Otherwise, the function may have failed, and the output parameter may contain invalid data that can cause any number of problems on the affected system.</p>

View File

@@ -3,7 +3,7 @@
"qhelp.dtd">
<qhelp>
<overview>
<include src="LeapYear.inc.qhelp" />
<include src="LeapYear.qhelp" />
<p>This query helps to detect when a developer allocates an array or other fixed-length data structure such as <code>std::vector</code> with 365 elements one for each day of the year.</p>
<p>Since leap years have 366 days, there will be no allocated element on December 31st at the end of a leap year; which will lead to a buffer overflow on a leap year.</p>

View File

@@ -54,7 +54,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
override predicate isWhitelisted() {
this.getConversion().(ParenthesisExpr).isParenthesised()
or
// Allow this assignment if all comparison operations in the expression that this
// 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.
@@ -62,21 +62,6 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
forex(ComparisonOperation op | op = getComparisonOperand*(this.getParent+()) |
not op.isParenthesised()
)
or
// Match a pattern like:
// ```
// if((a = b) && use_value(a)) { ... }
// ```
// where the assignment is meant to update the value of `a` before it's used in some other boolean
// subexpression that is guarenteed to be evaluate _after_ the assignment.
this.isParenthesised() and
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
var = this.getLValue().(VariableAccess).getTarget() and
access = var.getAnAccess() and
not access.isUsedAsLValue() and
parent.getRightOperand() = access.getParent*() and
parent.getLeftOperand() = this.getParent*()
)
}
}

View File

@@ -5,6 +5,7 @@
* @kind treemap
* @treemap.warnOn highValues
* @metricType externalDependency
* @precision medium
* @id cpp/external-dependencies
* @tags modularity
*/

View File

@@ -7,6 +7,7 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision very-high
* @id cpp/lines-of-code-in-files
* @tags maintainability
* complexity

View File

@@ -2,6 +2,6 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CommentedOutCodeMetricOverview.inc.qhelp" />
<include src="CommentedOutCodeReferences.inc.qhelp" />
<include src="CommentedOutCodeMetricOverview.qhelp" />
<include src="CommentedOutCodeReferences.qhelp" />
</qhelp>

View File

@@ -5,6 +5,7 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision high
* @id cpp/lines-of-commented-out-code-in-files
* @tags documentation
*/

View File

@@ -7,6 +7,7 @@
* @treemap.warnOn lowValues
* @metricType file
* @metricAggregate avg sum max
* @precision very-high
* @id cpp/lines-of-comments-in-files
* @tags maintainability
* documentation

View File

@@ -2,5 +2,5 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="FLinesOfDuplicatedCodeCommon.inc.qhelp" />
<include src="FLinesOfDuplicatedCodeCommon.qhelp" />
</qhelp>

View File

@@ -8,6 +8,7 @@
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @precision high
* @id cpp/duplicated-lines-in-files
* @tags testability
* modularity

View File

@@ -14,7 +14,7 @@ for a number of reasons.
</p>
</overview>
<include src="DuplicationProblems.inc.qhelp" />
<include src="DuplicationProblems.qhelp" />
<recommendation>

View File

@@ -5,6 +5,7 @@
* @treemap.warnOn lowValues
* @metricType file
* @metricAggregate avg sum max
* @precision medium
* @id cpp/tests-in-files
* @tags maintainability
*/

View File

@@ -1,3 +0,0 @@
char password[MAX_PASSWORD_LENGTH];
// read and verify password
memset(password, 0, MAX_PASSWORD_LENGTH);

View File

@@ -1,3 +0,0 @@
char password[MAX_PASSWORD_LENGTH];
// read and verify password
memset_s(password, MAX_PASSWORD_LENGTH, 0, MAX_PASSWORD_LENGTH);

View File

@@ -1,45 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Calling <code>memset</code> or <code>bzero</code> on a buffer to clear its contents may get optimized
away by the compiler if the buffer is not subsequently used. This is not desirable behavior if the buffer
contains sensitive data that could somehow be retrieved by an attacker.</p>
</overview>
<recommendation>
<p>Use alternative platform-supplied functions that will not get optimized away. Examples of such
functions include <code>memset_s</code>, <code>SecureZeroMemory</code>, and <code>bzero_explicit</code>.
Alternatively, passing the <code>-fno-builtin-memset</code> option to the GCC/Clang compiler usually
also prevents the optimization. Finally, you can use the public-domain <code>secure_memzero</code> function
(see references below). This function, however, is not guaranteed to work on all platforms and compilers.</p>
</recommendation>
<example>
<p>The following program fragment uses <code>memset</code> to erase sensitive information after it is no
longer needed:</p>
<sample src="MemsetMayBeDeleted-bad.c" />
<p>Because of dead store elimination, the call to <code>memset</code> may be removed by the compiler
(since the buffer is not subsequently used), resulting in potentially sensitive data remaining in memory.
</p>
<p>The best solution to this problem is to use the <code>memset_s</code> function instead of
<code>memset</code>:</p>
<sample src="MemsetMayBeDeleted-good.c" />
</example>
<references>
<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations">MSC06-C. Beware of compiler optimizations</a>.
</li>
<li>
USENIX: The Advanced Computing Systems Association:
<a href="https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.pdf">Dead Store Elimination (Still) Considered Harmfuls</a>
</li>
</references>
</qhelp>

View File

@@ -1,81 +0,0 @@
/**
* @name Call to `memset` may be deleted
* @description Using the `memset` function to clear private data in a variable that has no subsequent use
* can make information-leak vulnerabilities easier to exploit because the compiler can remove the call.
* @kind problem
* @id cpp/memset-may-be-deleted
* @problem.severity warning
* @precision high
* @tags security
* external/cwe/cwe-14
*/
import cpp
import semmle.code.cpp.dataflow.EscapesTree
import semmle.code.cpp.commons.Exclusions
import semmle.code.cpp.models.interfaces.Alias
class MemsetFunction extends Function {
MemsetFunction() {
this.hasGlobalOrStdOrBslName("memset")
or
this.hasGlobalOrStdName("wmemset")
or
this.hasGlobalName(["bzero", "__builtin_memset"])
}
}
predicate isNonEscapingArgument(Expr escaped) {
exists(Call call, AliasFunction aliasFunction, int i |
aliasFunction = call.getTarget() and
call.getArgument(i) = escaped.getUnconverted() and
(
aliasFunction.parameterNeverEscapes(i)
or
aliasFunction.parameterEscapesOnlyViaReturn(i) and
(call instanceof ExprInVoidContext or call.getConversion*() instanceof BoolConversion)
)
)
}
pragma[noinline]
predicate callToMemsetWithRelevantVariable(
LocalVariable v, VariableAccess acc, FunctionCall call, MemsetFunction memset
) {
not v.isStatic() and
// Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them
// out of this query.
not v.getUnspecifiedType() instanceof ReferenceType and
call.getTarget() = memset and
acc = v.getAnAccess() and
// `v` escapes as the argument to `memset`
variableAddressEscapesTree(acc, call.getArgument(0).getFullyConverted())
}
pragma[noinline]
predicate relevantVariable(LocalVariable v, FunctionCall call, MemsetFunction memset) {
exists(VariableAccess acc, VariableAccess anotherAcc |
callToMemsetWithRelevantVariable(v, acc, call, memset) and
// `v` is not only just used in the call to `memset`.
anotherAcc = v.getAnAccess() and
acc != anotherAcc and
not anotherAcc.isUnevaluated()
)
}
from FunctionCall call, LocalVariable v, MemsetFunction memset
where
relevantVariable(v, call, memset) and
not isFromMacroDefinition(call) and
// `v` doesn't escape anywhere else.
forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) |
isNonEscapingArgument(escape)
) and
// There is no later use of `v`.
not v.getAnAccess() = call.getASuccessor*() and
// Not using the `-fno-builtin-memset` flag
exists(Compilation c |
c.getAFileCompiled() = call.getFile() and
not c.getAnArgument() = "-fno-builtin-memset"
)
select call, "Call to " + memset.getName() + " may be deleted by the compiler."

View File

@@ -46,7 +46,7 @@ class UntrustedDataToExternalAPIConfig extends TaintTracking::Configuration {
UntrustedDataToExternalAPIConfig() { this = "UntrustedDataToExternalAPIConfig" }
override predicate isSource(DataFlow::Node source) {
exists(RemoteFlowSourceFunction remoteFlow |
exists(RemoteFlowFunction remoteFlow |
remoteFlow = source.asExpr().(Call).getTarget() and
remoteFlow.hasRemoteFlowSource(_, _)
)

View File

@@ -29,15 +29,9 @@ class QueryString extends EnvironmentRead {
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSource(Expr source) { source instanceof QueryString }
override predicate isSink(Element tainted) {
exists(PrintStdoutCall call | call.getAnArgument() = tainted)
}
override predicate isBarrier(Expr e) {
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
}
}
from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode

View File

@@ -27,10 +27,6 @@ class Configuration extends TaintTrackingConfiguration {
override predicate isSink(Element tainted) {
exists(SQLLikeFunction runSql | runSql.outermostWrapperFunctionCall(tainted, _))
}
override predicate isBarrier(Expr e) {
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
}
}
from

View File

@@ -1,5 +0,0 @@
unsigned limit = get_limit();
unsigned total = 0;
while (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop.
total += get_data();
}

View File

@@ -1,31 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
This rule finds relational comparisons between the result of an unsigned subtraction and the value <code>0</code>.
Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the
relational comparison ends up checking whether the result of the subtraction is equal to <code>0</code>.
This is probably not what the programmer intended.
</p>
</overview>
<recommendation>
<p>If a relational comparison is intended, consider casting the result of the subtraction to a signed type.
If the intention was to test for equality, consider replacing the relational comparison with an equality test.
</p>
</recommendation>
<example>
<sample src="UnsignedDifferenceExpressionComparedZero.c" />
</example>
<references>
<li>SEI CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules">INT02-C. Understand integer conversion rules</a>.
</li>
</references>
</qhelp>

View File

@@ -1,49 +0,0 @@
/**
* @name Unsigned difference expression compared to zero
* @description A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong.
* @kind problem
* @id cpp/unsigned-difference-expression-compared-zero
* @problem.severity warning
* @precision medium
* @tags security
* correctness
* external/cwe/cwe-191
*/
import cpp
import semmle.code.cpp.commons.Exclusions
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.controlflow.Guards
/** Holds if `sub` is guarded by a condition which ensures that `left >= right`. */
pragma[noinline]
predicate isGuarded(SubExpr sub, Expr left, Expr right) {
exists(GuardCondition guard |
guard.controls(sub.getBasicBlock(), true) and
guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false)
)
}
/** Holds if `sub` will never be negative. */
predicate nonNegative(SubExpr sub) {
not exprMightOverflowNegatively(sub.getFullyConverted())
or
// The subtraction is guarded by a check of the form `left >= right`.
exists(GVN left, GVN right |
// This is basically a poor man's version of a directional unbind operator.
strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and
strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and
isGuarded(sub, left.getAnExpr(), right.getAnExpr())
)
}
from RelationalOperation ro, SubExpr sub
where
not isFromMacroDefinition(ro) and
not isFromMacroDefinition(sub) and
ro.getLesserOperand().getValue().toInt() = 0 and
ro.getGreaterOperand() = sub and
sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and
not nonNegative(sub)
select ro, "Unsigned subtraction can never be negative."

View File

@@ -2,4 +2,4 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CleartextStorage.inc.qhelp" /></qhelp>
<include src="CleartextStorage.qhelp" /></qhelp>

View File

@@ -2,4 +2,4 @@
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="CleartextStorage.inc.qhelp" /></qhelp>
<include src="CleartextStorage.qhelp" /></qhelp>

View File

@@ -34,10 +34,6 @@ predicate sqlite_encryption_used() {
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSource(Expr source) {
super.isSource(source) and source instanceof SensitiveExpr
}
override predicate isSink(Element taintedArg) {
exists(SqliteFunctionCall sqliteCall |
taintedArg = sqliteCall.getASource() and

View File

@@ -93,7 +93,7 @@ class QuotedCommandInCreateProcessFunctionConfiguration extends DataFlow2::Confi
bindingset[s]
predicate isQuotedOrNoSpaceApplicationNameOnCmd(string s) {
s.regexpMatch("\"([^\"])*\"[\\s\\S]*") // The first element (path) is quoted
s.regexpMatch("\"([^\"])*\"(\\s|.)*") // The first element (path) is quoted
or
s.regexpMatch("[^\\s]+") // There are no spaces in the string
}

View File

@@ -189,7 +189,8 @@ class InitializationFunction extends Function {
// Field wise assignment to the parameter
any(Assignment e).getLValue() = getAFieldAccess(this.getParameter(i)) or
i =
this.(MemberFunction)
this
.(MemberFunction)
.getAnOverridingFunction+()
.(InitializationFunction)
.initializedParameter() or
@@ -326,37 +327,52 @@ class InitializationFunction extends Function {
// Return value is not a success code but the output functions never fail.
name.matches("_Interlocked%")
or
name =
[
// Functions that never fail, according to MSDN.
"QueryPerformanceCounter", "QueryPerformanceFrequency",
// Functions that never fail post-Vista, according to MSDN.
"InitializeCriticalSectionAndSpinCount",
// `rand_s` writes 0 to a non-null argument if it fails, according to MSDN.
"rand_s",
// IntersectRect initializes the argument regardless of whether the input intersects
"IntersectRect", "SetRect", "UnionRect",
// These functions appears to have an incorrect CFG, which leads to false positives
"PhysicalToLogicalDPIPoint", "LogicalToPhysicalDPIPoint",
// Sets NtProductType to default on error
"RtlGetNtProductType",
// Our CFG is not sophisticated enough to detect that the argument is always initialized
"StringCchLengthA",
// All paths init the argument, and always returns SUCCESS.
"RtlUnicodeToMultiByteSize",
// All paths init the argument, and always returns SUCCESS.
"RtlMultiByteToUnicodeSize",
// All paths init the argument, and always returns SUCCESS.
"RtlUnicodeToMultiByteN",
// Always initializes argument
"RtlGetFirstRange",
// Destination range is zeroed out on failure, assuming first two parameters are valid
"memcpy_s",
// This zeroes the memory unconditionally
"SeCreateAccessState",
// Argument initialization is optional, but always succeeds
"KeGetCurrentProcessorNumberEx"
]
// Functions that never fail, according to MSDN.
name = "QueryPerformanceCounter"
or
name = "QueryPerformanceFrequency"
or
// Functions that never fail post-Vista, according to MSDN.
name = "InitializeCriticalSectionAndSpinCount"
or
// `rand_s` writes 0 to a non-null argument if it fails, according to MSDN.
name = "rand_s"
or
// IntersectRect initializes the argument regardless of whether the input intersects
name = "IntersectRect"
or
name = "SetRect"
or
name = "UnionRect"
or
// These functions appears to have an incorrect CFG, which leads to false positives
name = "PhysicalToLogicalDPIPoint"
or
name = "LogicalToPhysicalDPIPoint"
or
// Sets NtProductType to default on error
name = "RtlGetNtProductType"
or
// Our CFG is not sophisticated enough to detect that the argument is always initialized
name = "StringCchLengthA"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlMultiByteToUnicodeSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteN"
or
// Always initializes argument
name = "RtlGetFirstRange"
or
// Destination range is zeroed out on failure, assuming first two parameters are valid
name = "memcpy_s"
or
// This zeroes the memory unconditionally
name = "SeCreateAccessState"
)
}
}
@@ -459,9 +475,12 @@ class ConditionalInitializationCall extends FunctionCall {
fa.getASuccessor+() = result
) and
result =
this.getArgument(getTarget(this)
.(ConditionalInitializationFunction)
.conditionallyInitializedParameter(_)).(AddressOfExpr).getOperand()
this
.getArgument(getTarget(this)
.(ConditionalInitializationFunction)
.conditionallyInitializedParameter(_))
.(AddressOfExpr)
.getOperand()
}
Variable getStatusVariable() {

View File

@@ -8,7 +8,6 @@
* @tags reliability
* security
* external/cwe/cwe-242
* external/cwe/cwe-676
*/
import cpp

View File

@@ -140,9 +140,12 @@ class FopenCreationExpr extends FileCreationExpr {
class FopensCreationExpr extends FileCreationExpr {
FopensCreationExpr() {
this.getTarget().getName() = ["fopen_s", "_wfopen_s"] and
exists(string name | name = this.getTarget().getName() |
name = "fopen_s" or
name = "_wfopen_s"
) and
exists(string mode |
mode = ["w", "a"] and
(mode = "w" or mode = "a") and
this.getArgument(2).getValue().matches(mode + "%")
)
}

View File

@@ -1,11 +0,0 @@
/**
* @id cpp/summary/lines-of-code
* @name Total lines of C/C++ code in the database
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
*/
import cpp
select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode())

View File

@@ -1,7 +0,0 @@
if(len<0) return 1;
memset(dest, source, len); // GOOD: variable `len` checked before call
...
memset(dest, source, len); // BAD: variable `len` checked after call
if(len<0) return 1;

View File

@@ -1,28 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Checking the function argument after calling the function itself. This situation looks suspicious and requires the attention of the developer. It may be necessary to add validation before calling the function</p>
</overview>
<recommendation>
<p>We recommend checking before calling the function.</p>
</recommendation>
<example>
<p>The following example demonstrates an erroneous and fixed use of function argument validation.</p>
<sample src="LateCheckOfFunctionArgument.c" />
</example>
<references>
<li>
CWE Common Weakness Enumeration:
<a href="https://cwe.mitre.org/data/definitions/20.html"> CWE-20: Improper Input Validation</a>.
</li>
</references>
</qhelp>

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